Subclassing Controls
-
Moin,
ich habe mir eine GUI zusammengebastelt (Anfänger) und benutze Static-Controls mit Bimaps als Button.
Diese Steuerelemente habe ich nun "gesubclassed", damit sie wie Buttons reagieren.
Funktionieren tut es soweit, jedoch bin ich mir nicht sicher, ob das so alles seine Richtigkeit hat.
Deshalb meine Frage/Bitte an euch:
Ist das so OK mit dem Subclassing, oder sollte ich das ganze lieber anders machen ... ?
Ich bin über die globalen Variablen der Fenster nicht so ganz glücklich, oder ist das schon i.O. so ...
Außerdem wird immer wieder das Bitmap an das Static-Control gesendet wenn die Maus über den Button fährt, das geht doch bestimmt auch anders, oder ?Wäre für ein paar Tips und Ratschläge sehr dankbar.

#include <windows.h> //#include <commctrl.h> //#pragma comment(lib, "comctl32.lib") #define IDS_CLOSE 1 #define IDS_MINIMIZE 2 #define IDB_START 3 #define IDB_EXIT 4 #define IDB_SELDIR 5 #define IDE_NAME 7 #define IDE_DIR 8 LRESULT CALLBACK WindowProc (HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK ButtonProc(HWND, UINT, WPARAM, LPARAM); void CreateControls(HWND, HINSTANCE); TCHAR szClassName[] = TEXT("MyClass") ; HINSTANCE hInstance = GetModuleHandle(NULL); WNDPROC STATIC_PROC[5]; HBITMAP hBitmap[14]; HWND hWnd ; HWND hBoxClose; HWND hBoxMinimize; HWND hBtnStart; HWND hBtnExit; HWND hBtnSelDir; HWND hEdtDateiname; HWND hEdtDlDir; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) { MSG nMsg ; WNDCLASSEX WndClass ; WndClass.style = CS_HREDRAW | CS_VREDRAW | 0x00020000 ; WndClass.hInstance = hInstance ; WndClass.lpfnWndProc = WindowProc ; WndClass.cbSize = sizeof (WNDCLASSEX) ; WndClass.cbClsExtra = 0 ; WndClass.cbWndExtra = 0 ; WndClass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; WndClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; WndClass.hCursor = LoadCursor (NULL, IDC_ARROW) ; WndClass.lpszMenuName = NULL ; WndClass.hbrBackground = (HBRUSH) CreatePatternBrush((HBITMAP)LoadImage(NULL, TEXT("backpic.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE)) ; WndClass.lpszClassName = szClassName ; if (!RegisterClassEx (&WndClass)) return 0 ; //InitCommonControls(); hWnd = CreateWindow(szClassName, TEXT("CS Kino"), //WS_OVERLAPPEDWINDOW, WS_POPUP, 400, 200, 635, 476, NULL, NULL, hInstance, NULL); ShowWindow (hWnd, nCmdShow); UpdateWindow (hWnd); while (GetMessage (&nMsg, NULL, 0, 0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } return nMsg.wParam; } LRESULT CALLBACK WindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hDC ; HRGN hRgn; PAINTSTRUCT ps; switch (message) { case WM_CREATE : // Steuerelemente erstellen CreateControls(hWnd, hInstance); // Fensterecken abrunden hRgn = CreateRoundRectRgn(0, 0, 635, 476, 6, 6); SetWindowRgn(hWnd, hRgn, TRUE); return 0 ; case WM_PAINT : hDC = BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps); return 0 ; case WM_NOTIFY : return 0; case WM_COMMAND : switch (wParam) { case IDB_EXIT : DestroyWindow(hWnd); break; case IDS_CLOSE : DestroyWindow(hWnd); break; case IDS_MINIMIZE : ShowWindow(hWnd, SW_MINIMIZE); break; } return 0; case WM_LBUTTONDOWN : // Fenster-Drag SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, (LPARAM)NULL) ; return 0 ; case WM_DESTROY : // Aufräumen ... for (int i = 0; i != 10; i++) { DeleteObject(hBitmap[i]); } PostQuitMessage (0); return 0 ; } return DefWindowProc (hWnd, message, wParam, lParam); } void CreateControls(HWND hWnd, HINSTANCE hInstance) { char Bitmaps[14][20] = {TEXT("close0.bmp"), TEXT("close1.bmp"), TEXT("close2.bmp"), TEXT("min0.bmp"), TEXT("min1.bmp"), TEXT("min2.bmp"), TEXT("BtnStrtD.bmp"), TEXT("BtnStrtH.bmp"), TEXT("BtnStpD.bmp"), TEXT("BtnStpH.bmp"), TEXT("BtnCnclD.bmp"), TEXT("BtnCnclH.bmp"), TEXT("BtnFoldD.bmp"), TEXT("BtnFoldH.bmp")}; // Bitmaps laden for (int i = 0; i != 14; i++) { hBitmap[i] = (HBITMAP)LoadImage(NULL, Bitmaps[i], IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); } ///////////////////////////// // Steuerelemente erstellen ///////////////////////////// // Buttons hBoxClose = CreateWindow(TEXT("STATIC"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_BITMAP | SS_CENTERIMAGE | SS_NOTIFY, 585, 0, 43, 17, hWnd, (HMENU) IDS_CLOSE, hInstance, NULL); hBoxMinimize = CreateWindow(TEXT("STATIC"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_BITMAP | SS_CENTERIMAGE | SS_NOTIFY, 559, 0, 26, 17, hWnd, (HMENU) IDS_MINIMIZE, hInstance, NULL); hBtnStart = CreateWindow(TEXT("STATIC"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_BITMAP | SS_CENTERIMAGE | SS_NOTIFY, 520, 350, 80, 27, hWnd, (HMENU) IDB_START, hInstance, NULL); hBtnExit = CreateWindow(TEXT("STATIC"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_BITMAP | SS_CENTERIMAGE | SS_NOTIFY, 520, 390, 80, 27, hWnd, (HMENU) IDB_EXIT, hInstance, NULL); hBtnSelDir = CreateWindow(TEXT("STATIC"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_BITMAP | SS_CENTERIMAGE | SS_NOTIFY, 230, 365, 40, 27, hWnd, (HMENU) IDB_SELDIR, hInstance, NULL); // Edit Controls hEdtDateiname = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_LEFT, 25, 320, 150, 20, hWnd, (HMENU) IDE_NAME, hInstance, NULL); hEdtDlDir = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_LEFT, 25, 368, 200, 20, hWnd, (HMENU) IDE_DIR, hInstance, NULL); // Bitmaps setzen SendMessage(hBoxClose, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[0]); SendMessage(hBoxMinimize, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[3]); SendMessage(hBtnStart, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[6]); SendMessage(hBtnExit, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[8]); SendMessage(hBtnSelDir, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[12]); // Subclassing der Steuerelemente STATIC_PROC[0] = (WNDPROC)SetWindowLong(hBoxClose, GWLP_WNDPROC, (long)ButtonProc); STATIC_PROC[1] = (WNDPROC)SetWindowLong(hBoxMinimize, GWLP_WNDPROC, (long)ButtonProc); STATIC_PROC[2] = (WNDPROC)SetWindowLong(hBtnStart, GWLP_WNDPROC, (long)ButtonProc); STATIC_PROC[3] = (WNDPROC)SetWindowLong(hBtnExit, GWLP_WNDPROC, (long)ButtonProc); STATIC_PROC[4] = (WNDPROC)SetWindowLong(hBtnSelDir, GWLP_WNDPROC, (long)ButtonProc); } LRESULT CALLBACK ButtonProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_MOUSEHOVER: if (hDlg == hBoxClose) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[1]); else if (hDlg == hBoxMinimize) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[4]); else if (hDlg == hBtnStart) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[7]); else if (hDlg == hBtnExit) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[9]); else if (hDlg == hBtnSelDir) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[13]); break; case WM_MOUSELEAVE: if (hDlg == hBoxClose) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[0]); else if (hDlg == hBoxMinimize) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[3]); else if (hDlg == hBtnStart) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[6]); else if (hDlg == hBtnExit) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[8]); else if (hDlg == hBtnSelDir) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[12]); break; case WM_LBUTTONUP: if (hDlg == hBtnStart) SetWindowPos(hDlg, HWND_TOP, 520, 350, 80, 27, SWP_SHOWWINDOW); else if (hDlg == hBtnExit) { SetWindowPos(hDlg, HWND_TOP, 520, 390, 80, 27, SWP_SHOWWINDOW); SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[9]); Sleep(100); SendMessage(GetParent(hDlg), WM_DESTROY, 0, 0); } else if (hDlg == hBtnSelDir) SetWindowPos(hDlg, HWND_TOP, 230, 365, 40, 27, SWP_SHOWWINDOW); break; case WM_LBUTTONDOWN: if (hDlg == hBoxClose) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[2]); else if (hDlg == hBoxMinimize) SendMessage(hDlg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap[5]); else if (hDlg == hBtnStart) SetWindowPos(hDlg, HWND_TOP, 521, 351, 78, 25, SWP_SHOWWINDOW); else if (hDlg == hBtnExit) SetWindowPos(hDlg, HWND_TOP, 521, 391, 78, 25, SWP_SHOWWINDOW); else if (hDlg == hBtnSelDir) SetWindowPos(hDlg, HWND_TOP, 231, 366, 40, 27, SWP_SHOWWINDOW); Sleep(100); break; case WM_MOUSEMOVE: TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_HOVER|TME_LEAVE; // TME_LEAVE 'or'ed tme.dwHoverTime = 10; //HOVER_DEFAULT; tme.hwndTrack = hDlg; TrackMouseEvent(&tme); break; case WM_DESTROY: PostQuitMessage(0); break; break; } if (hDlg == hBoxClose) return CallWindowProc(STATIC_PROC[0], hDlg, message, wParam, lParam); else if (hDlg == hBoxMinimize) return CallWindowProc(STATIC_PROC[1], hDlg, message, wParam, lParam); else if (hDlg == hBtnStart) return CallWindowProc(STATIC_PROC[2], hDlg, message, wParam, lParam); else if (hDlg == hBtnExit) return CallWindowProc(STATIC_PROC[3], hDlg, message, wParam, lParam); else if (hDlg == hBtnSelDir) return CallWindowProc(STATIC_PROC[4], hDlg, message, wParam, lParam); return CallWindowProc(STATIC_PROC[0], hDlg, message, wParam, lParam); }Ich hoffe es ist nicht zu unübersichtlich ...

Gruß
Greenhorn
-
Uff...das ist aber viel Code
.Also mal vorweg: Es macht glaube ich Sinn, die Bitmaps nur einmal zu laden und am Ende freizugeben, da man schon mal öfters mit der Maus drüber hüpft. Weiterhin kannst Du mittels SetWindowLongPtr und GWLP_USERDATA die globalen Variablen umgehen
. Wenn Du C++ kannst, kannst Du Dir eigene Controls, basierend auf einer eigens definierten WndProc/Fensterklasse schreiben und diese in einer Klasse kapseln. Hab ich mal gemacht. Ist später wesentlich angenehmer bei der Verwendung, aber schon einiges an Arbeit, sieht dann z.B. so aus:static CButtonControl cBtn; // ... cBtn.Create(...); cBtn.SetBitmaps(...); cBtn.SetRegion(...); cBtn.EnableNotifyEx(...); // ... // Optional: cBtn.Destroy(); oder halt autom. via Destruktor.
-
Dieser Code ist unsinnig. Warum mappst Du alles auf eine WndProc?
Versuche das verhalten so zu standartisieren, dass die WndProc nicht von den einzelnen Instanen abhängig wird.
Dem Hinweis auf GWLP_USERDATA von Codefinder solltest Du nachgehen. Du könntest dort eine Struktur allokieen, in der Du sowohl die alte WndProc speicherst als auch die Bitmap...
-
Hallo,
vielen Dank für eure Antworten.

Also war mein Gefühl schon richtig, dass das nicht das Gelbe vom Ei ist ...

Wie gesagt, bin noch Anfänger in C++ und schmökere halt nebenbei noch den Petzold.
Wahrscheinlich verlange ich mir wieder mal zuviel auf einmal ab ...Also das mit der eingenen Fenster/Button Klasse habe ich mir auch schon überlegt, aber weiss nicht so recht wie ich da herangehen soll, also welche Strukturen brauche ich usw.
Vor der Arbeit scheue ich mich nicht, daran soll's nicht liegen ...Ansonsten werde ich mir mal das mit GWLP_USERDATA ansehen und nach Beispielen suchen.
Habe bei M$ auch gesehen, dass man für's Subclassing lieber SetWindowSubclass benutzen soll.
Hmmm ...Gruß
Greenhorn
-
Benutze keine Static-Controls, sondern erstelle Buttons (Klasse "Button") und zeichne sie selbst mit Ownerdrawing.
Da musst du weder Subclassing betreiben und kannst das Zeichnen auch auf Funktionen auslagern, die du in WM_DRAWITEM aufrufst.Grüße, Xantus
-
Danke Xantus, das ist auch eine Alternative, werd's probieren
(... oder probiert es mich ???)Gruß
Greenhorn