Nächster Schritt - Ein eigener Button
-
Hi Leute,
ich bins mal wieder. Da es mit dem eigenen Fenster(siehe http://www.c-plusplus.net/forum/327357)
klappt, wollte ich noch einen eigenen Button erstellen. Das Problem, ich weiss nicht
so recht, wie ich anfangen muss. Vom Verständnis her ist das Problem weniger bei BS_OWNERDRAW und WM_DRAWITEM, sondern eher beim Erstellen und Anzeigen.
Genauer gesagt, ich weiss nicht so recht wie ich das mit den HDCs machen muss.Meine ersten Ansätze waren:
- Einen temporären HDC und ein HBITMAP erstellen
- Mit SelectObject HBITMAP auswählen
- Mit BitBlt() weiter machenJedoch weiss ich nicht, was ich jetzt genau alles brauche(ein ScreenDC und noch ne temporäre HDC?), und in welcher "Reihenfolge" es passieren muss.
Ich möchte keinen Code "basteln", in dem ich verschiedene Codeschnipsel aus dem Netz hole und mich dann wundere, warum ich haufenweise Fehler bekomme.
Ich würde gerne das Coden, was ich verstehe. Nur finde ich in der MSDN keinen richtigen Ansatz. Ich hoffe ihr versteht mich.
Danke vorab fürs Antworten
-
Ein Window wird nur in WM_PAINT gezeichnet. Du bekommst den notwendigen DC frei Haus mit der WM_PAINT Nachricht.
Wenn Du mit WM_DRAWITEM arbeitest bekommst Du den DC von dieser Nachricht. Lies die MSDN!
-
Konnte jetzt erst antworten.
So, ok in der MSDN hab ich bei der DRAWITEMSTRUCT den HDC gefunden,
der für die Durchführung von Zeichenoperationen verwendet
werden muss.A handle to a device context; this device context must be used when performing drawing operations on the control.
Das heißt ja, das ich im grunde einfach eine Bitmap in nen temporären HDC laden und sie dann, entsprechend dem Status des
Buttons in den HDC(DRAWITEMSTRUCT->HDC) mit BitBlt() und SRCCOPY setzen muss,
falls ich es richtig verstanden habe oder?
-
Ich hab es jetzt mal so gemacht, da es hier http://www.c-plusplus.net/forum/279713-full ja auch so gesagt wird.
Das Problem ist nur, ich kann nicht sagen, ob es klappt oder nicht, da die Nachricht WM_DRAWITEM erst gar nicht bearbeitet wird. Habe mal zum test
ne MessageBox eingebaut, jedoch kommt nichts.
Wo kann der Fehler liegen?Das Hauptfenster sieht so aus:
hWnd = CreateWindowEx(WS_EX_LAYERED, "MyClass", "", 0, GetSystemMetrics(SM_CXSCREEN) / 2 - 400, GetSystemMetrics(SM_CYSCREEN) / 2 - 300, 0, 0, NULL, NULL, hInstance, NULL);
Der Button sieht so aus:
hButton = CreateWindow("Button", "", BS_OWNERDRAW | WS_CHILD | WS_VISIBLE, 50, 40, 60, 40, hWnd, (HMENU)1, hInstance, NULL);
Weis jemand weiter?
-
Keiner Da?
-
Kann mir denn keiner dabei helfen? Ich habe jetzt noch mal ein neues Projekt angefangen, wo ich als erstes nur das
Grundgerüst(ein normales Fenster) erstellt habe.
Jetzt habe ich dazu ein Button
mit BS_OWNERDRAW erstellt und will diesen in der WM_DRAWITEM zeichnen. Jedoch habe
ich auch hier das Problem, das er erst garnicht in die WM_DRAWITEM kommt.Ich weiss echt nicht weiter.
Bitte helft mir.Hier mal der ganze Code:
#include <Windows.h> #include <GdiPlus.h> using namespace Gdiplus; GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; HWND g_hWnd; HWND g_hbutton; MSG g_msg; HBITMAP hBackground = 0; LRESULT CALLBACK DSProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, char* CmdLine, int iCmdShow) { WNDCLASSEX dsClass; dsClass.cbSize = sizeof(WNDCLASSEX); dsClass.style = CS_HREDRAW | CS_VREDRAW; dsClass.lpfnWndProc = DSProc; dsClass.cbClsExtra = 0; dsClass.cbWndExtra = 0; dsClass.hInstance = hInstance; dsClass.hIcon = NULL; dsClass.hCursor = NULL; dsClass.hbrBackground = (HBRUSH) COLOR_HIGHLIGHT +1; dsClass.lpszMenuName = NULL; dsClass.lpszClassName = "MyClass"; dsClass.hIconSm = NULL; RegisterClassEx(&dsClass); g_hWnd = CreateWindow("MyClass", "TEST", WS_OVERLAPPEDWINDOW, GetSystemMetrics(SM_CXSCREEN) / 2 - 400, GetSystemMetrics(SM_CYSCREEN) / 2 - 300, 800, 600, NULL, NULL, hInstance, NULL); ShowWindow(g_hWnd, iCmdShow); UpdateWindow(g_hWnd); g_hbutton = CreateWindow("BUTTON", "", BS_OWNERDRAW | WS_CHILD, 100, 50, 100, 50, g_hWnd, NULL, GetModuleHandle(NULL), NULL); //GDI+ initialisieren GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); Bitmap background(L"Disable.png"); background.GetHBITMAP(Color(), &hBackground); while(GetMessage(&g_msg, NULL, 0, 0)) { TranslateMessage(&g_msg); DispatchMessage(&g_msg); } //GDI+ runterfahren GdiplusShutdown(gdiplusToken); return (int) g_msg.wParam; } LRESULT CALLBACK DSProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdcMem; LPDRAWITEMSTRUCT dis; switch(message) { case WM_DESTROY: PostQuitMessage(0); break; case WM_DRAWITEM: { //MessageBox(NULL, "Bin drinne", "OK", 0); Hier kommt er erst garnicht rein. Ich weiss nicht wieso ??? dis = (LPDRAWITEMSTRUCT) lParam; hdcMem = CreateCompatibleDC(dis->hDC); SelectObject(hdcMem, hBackground); BitBlt(dis->hDC, 100, 50, 100, 50, hdcMem, 0, 0, SRCCOPY); DeleteDC(hdcMem); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
-
Du musst deinen Button erst einmal sichtbar machen, entweder durch ShowWindow oder durch den Style WS_VISIBLE.
-
Dein Programm leaked.
Du musst die Bitmap, die Du zurück bekommst bei SelectObject auch wieder zurück selektieren. Sonst geht diese verloren. Ein typisches GDI-Leak.
-
Hi, erstmal danke für die schnelle Antwort.
@MFK
Stimmt, habe ich voll übersehen. Jetzt sehe ich den Bereich, wo der Button sein muss. Allerdings ist dieser nur weiß.@Martin Richter
Ich habe dich nicht so richtig verstanden, was genau du meinst.
Meinst du, das ich nach dem AufrufSelectObject(hdcMem, hBackground); BitBlt(dis->hDC, 100, 50, 100, 50, hdcMem, 0, 0, SRCCOPY);
SelectObject erneut aufrufen muss, da die Bitmap sonst weg ist?
Meinst du das mit zurück selektieren?
-
Habe gerade noch mal bei der MSDN nachgeschaut unter SelectObject.
The SelectObject function selects an object into the specified device context (DC). The new object replaces the previous object of the same type.
...
...Return value
If the selected object is not a region and the function succeeds, the return value is a handle to the object being replaced.
Ich bekomme ja ein Handle auf das Objekt zurück. Meinst du dieses mit zurück selektieren?
-
Genau! Das ist der relevante Abschnitt in der MSDN.
Sonst wird die Bitmap (1x1 pixel groß), die vei CreateCompatibleDC erzeugt wird nicht wieder freigegeben, weil Du sie wegwirfst. Deine Bitmap wird auch nicht zerstört weil noch in Benutzung...
-
Wie genau müsste ich es dann machen?
Habe den Teil mit zurück selektieren irgend wie noch nicht so ganz verstandenWäre es vielleicht besser, wenn ich CreateCompatibleBitmap mit der entsprechenden Größe nehmen würde?
-
Wäre schön, wenn ich für diesen Teil noch hilfe kriegen würde
-
Remarks
This function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object.
savedObject = SelectObject(...) ... SelectObject(savedObject)
-
[quote="RED-BARON"]
savedObject = SelectObject(...) ... SelectObject(savedObject)
Das habe ich schon probiert, jedoch passiert nichts. Es bleibt gleich.
-
Ich habe es jetzt wie volgt gemacht und mich dabei an dem Post von Don Carsto(http://www.c-plusplus.net/forum/279713-full) orientiert.
Das sieht dann so aus: http://s1.directupload.net/images/140916/39yszfq8.jpg
Da die Bitmap eine PNG ist, habe ich es mit AlphaBlend gemacht.
Das sieht dann so aus: http://s14.directupload.net/images/140916/gaiux9fh.jpgMan sieht, dass die weisse Fläche stört. Jetzt mal ohne die Bitmap
Das sieht dann so aus: http://s1.directupload.net/images/140916/ozv3y96p.jpgKann mir jemand sagen, wie ich diese weiße Fläche weg bekomme?
-
Hier kurz noch die Code-Stelle:
rapo1 = GetDC(hWnd); rapo2 = CreateCompatibleDC(rapo1); SelectObject(rapo2, hBackground); //BitBlt(rapo1, 100, 50, 100, 50, rapo2, 0, 0, SRCCOPY); //AlphaBlend(rapo1, 100, 50, 100, 50, rapo2, 0, 0, 100, 50, blend); DeleteObject(rapo2); ReleaseDC(hWnd, rapo1);
-
Falsch. Es geht um den Rückgabewert von SelectObject!
-
Martin, weisst du, wie ich dieses weiße Rechteck weg bekomme?
-
Ich habe es jetzt transparent bekommen, indem ich WM_CTLCOLORBTN behandle.
Jetzt ist da nur noch ein Problem.
Jedes mal, wenn ich auf den Button klicke, zeichnet er ihn sozusagen neu auf die Bitmap,
sodass man an dem Rand sehen kann, das die Bitmap "überlappt".
Ich glaube, das kommt von dem, was Martin Richter angesprochen hat.Jedenfalls würde ich mich freuen, wenn da jemand weiter weiss.
-
Hier kurz was ich meine. Hoffe man kann es einigermaßen erkennen.
http://s14.directupload.net/images/140917/7d75k4d2.jpg
Das Bild unten ist nach mehrmaligem klicken.
An den Rändern links-rechts kann man erkennen, das es überlappt.