Probleme beim Kapseln einer nicht statischen Callback-Funtion
-
Hallo,
ich hab mich vor ein paar Tagen bei CodeGuru durchgeschlagen auf der Suche nach einem Beipiel wie man sich Controlls mit OnMouseOver-Effekt erstellt.
Nach ein bischen Recherche wurde ich dann auch fündig.mein Beispiel klappte ganz gut:
Ich passte hier mal der reihe nach meinen Source:
Hier meine template.cpp
#include "template.h" #include "skin/skin.h" HINSTANCE hMainInstance=NULL; BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(uMsg==WM_INITDIALOG) { SetWindowText(hwnd, APPLICATION_ABOUT_NAME); return TRUE; }//WM_INITDIALOG else if(uMsg==WM_COMMAND) { }//WM_COMMAND else if(uMsg==WM_CLOSE) { EndDialog(hwnd,1); return 0; }// WM_CLOSE else { return FALSE; }//ELSE return TRUE; } LRESULT CALLBACK NewStaticProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(uMsg == WM_MOUSEMOVE) { if (!bMouseInWindow) { bMouseInWindow = true; SendMessage(hWnd, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmapOkOver ); TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE | TME_HOVER; tme.hwndTrack = hWnd; tme.dwHoverTime = HOVER_DEFAULT; TrackMouseEvent(&tme); }else return CallWindowProc(wpOrigButtonOkProc, hWnd, uMsg, wParam, lParam); }else if(uMsg == WM_MOUSELEAVE) { bMouseInWindow = false; SendMessage(hWnd, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmapOk); }else return CallWindowProc(wpOrigButtonOkProc, hWnd, uMsg, wParam, lParam); return true; } BOOL CALLBACK MainDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { if(Message==WM_INITDIALOG) { SetWindowText(hwnd, APPLICATION_NAME); hBitmapOk = LoadBitmap(hMainInstance, MAKEINTRESOURCE(IDB_OK)); hBitmapOkOver = LoadBitmap(hMainInstance, MAKEINTRESOURCE(IDB_OK_OVER)); hWndStaticButtonOk = GetDlgItem(hwnd, IDC_STATICOK); SendMessage(hWndStaticButtonOk, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmapOk ); wpOrigButtonOkProc = (WNDPROC) SetWindowLong(hWndStaticButtonOk, GWL_WNDPROC, (LONG) NewStaticProc); } else if(Message==WM_COMMAND) { if(wParam==IDC_STATIC1){} } else if(Message==WM_CLOSE) { DestroyWindow( hwnd ); return 0; } else if(Message==WM_DESTROY) { PostQuitMessage (0); return 0; } else{ return FALSE; } return TRUE; } BOOL CALLBACK SplashDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { if(Message==WM_INITDIALOG) { // sets the icon of the application displayed // in the upper left corner SetClassLong(hwnd, GCL_HICON, (LONG)LoadIcon(hMainInstance, (LPCTSTR)IDI_TEMPLATE)); SetWindowText(hwnd, APPLICATION_NAME); SetTimer(hwnd,1,2000,NULL); // Skin-Init-Beginn CSkin skSkin(IDR_SPLASH, IDB_SPLASH); skSkin.Hook(hwnd); skSkin.Enable(true); int iWidth = skSkin.Width(); int iHeight = skSkin.Height(); int iSw = (WORD)GetSystemMetrics(SM_CXSCREEN); int iSh = (WORD)GetSystemMetrics(SM_CYSCREEN); RECT rc = { (iSw - iWidth)/2, (iSh - iHeight)/2, iWidth, iHeight }; ShowWindow(hwnd, SW_SHOW); MSG mMsg; while( GetMessage(&mMsg, NULL, 0, 0) ) { if( PeekMessage(&mMsg, 0, 0, 0, PM_REMOVE) ) if( mMsg.message == WM_QUIT ) break; TranslateMessage( &mMsg ); DispatchMessage( &mMsg ); } DestroyWindow(hwnd); // Skin-Init-Ende return TRUE; }//WM_INITDIALOG else if (Message == WM_TIMER) { KillTimer(hwnd,1); EndDialog(hwnd,IDD_SPLASH); DialogBox(hMainInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc); }//WM_TIMER else if(Message==WM_COMMAND) { }//WM_COMMAND else if(Message==WM_CLOSE) { EndDialog(hwnd,1); return 0; }// WM_CLOSE else { return FALSE; }//ELSE return TRUE; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { hMainInstance = hInstance; // show splashscreen on startup ? DEBUG_LOAD_SPLASH = false; if(DEBUG_LOAD_SPLASH) { return DialogBox(hInstance, MAKEINTRESOURCE(IDD_SPLASH), NULL, SplashDlgProc); }else { return DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc); } }Hier die dazugehörige header file
#pragma once #define _WIN32_WINNT 0x0400 #define WINVER 0x0500 #define WIN32_LEAN_AND_MEAN #define STRICT #include <windows.h> #include "resource.h" // debug flags BOOL DEBUG_LOAD_SPLASH; // contants strings static char APPLICATION_NAME[] = "Template"; static char APPLICATION_ABOUT_NAME[] = "About Template"; HWND hMain = NULL; HWND hWndStaticButtonOk = NULL; BOOL bMouseInWindow = FALSE; HINSTANCE hInst = NULL; WNDPROC wpOrigButtonOkProc = NULL; HBITMAP hBitmapOk = NULL; HBITMAP hBitmapOkOver = NULL;Diese Beispiel läuft problemlos. Der Nachteil dieser Methode is jedoch ersichtlich. Ich muss für jedes controll ne extra WndProc-Variable anlegen oder sogar eine eigene CallBackFunktion.
Es gibt da verschiedenste Möglichkeiten aber die gefallen mir alle nicht.Also hab ich mir überlegt das ganze in eine Klasse zu packen um anschließen für jedes Controll das ich erstellen will einfach ein neues Objekt meiner Klasse zu erstellen. Zumindest WILL ich das jetzt so machen

Gut gesagt getan:
Hier meine Entprechende Klasse:
Button.cpp
#include "Button.h" // Default-Konstruktor Button::Button(void) { } // Custom-Konstruktor Button::Button(HINSTANCE hMainInstance, HWND hwnd, int idButtonNorm, int idButtonOver, int idStatic) { HWND hMain = NULL; HWND hWndStaticButtonOk = NULL; BOOL bMouseInWindow = FALSE; HINSTANCE hInst = NULL; WNDPROC wpOrigButtonOkProc = NULL; HBITMAP hBitmapOk = NULL; HBITMAP hBitmapOkOver = NULL; hBitmapOk = LoadBitmap(hMainInstance, MAKEINTRESOURCE(IDB_OK)); hBitmapOkOver = LoadBitmap(hMainInstance, MAKEINTRESOURCE(IDB_OK_OVER)); hWndStaticButtonOk = GetDlgItem(hwnd, IDC_STATICOK); SendMessage(hWndStaticButtonOk, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmapOk ); wpOrigButtonOkProc = (WNDPROC) SetWindowLong(hWndStaticButtonOk, GWL_WNDPROC, (LONG)NewStaticProc); } LRESULT CALLBACK Button::NewStaticProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(uMsg == WM_MOUSEMOVE) { if (!bMouseInWindow) { bMouseInWindow = true; SendMessage(hWnd, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmapOkOver ); TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE | TME_HOVER; tme.hwndTrack = hWnd; tme.dwHoverTime = HOVER_DEFAULT; TrackMouseEvent(&tme); }else return CallWindowProc(wpOrigButtonOkProc, hWnd, uMsg, wParam, lParam); }else if(uMsg == WM_MOUSELEAVE) { bMouseInWindow = false; SendMessage(hWnd, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmapOk); }else return CallWindowProc(wpOrigButtonOkProc, hWnd, uMsg, wParam, lParam); return true; }und noch die Header file:
#pragma once #define _WIN32_WINNT 0x0400 #define WINVER 0x0500 #define WIN32_LEAN_AND_MEAN #define STRICT #include <windows.h> #include "resource.h" class Button; class Button { private: // Instanzvariablen HWND hMain; HWND hWndStaticButtonOk; BOOL bMouseInWindow; HINSTANCE hInst; WNDPROC wpOrigButtonOkProc; HBITMAP hBitmapOk; HBITMAP hBitmapOkOver; public: // Prototypen // Konstruktoren Button(void); Button(HINSTANCE hMainInstance, HWND hwnd, int idButtonNorm, int idButtonOver, int idStatic); // Destruktoren ~Button(void); // Funktionen LRESULT CALLBACK NewStaticProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); };So, ja ich weiß im Konstruktor meiner Klasse finden noch einige schwachsinnige Sachen statt, aber das ist nicht das Problem.
Was sich im Beispiel 1 noch problemlos kompilieren lie´ße geht nun nicht mehr
Anscheind kann man nicht statische Callback-Funtionen nicht so ohne Weiteres in Classen verwenden. Ich hab schon ein bischen nachgeforscht und herausgefunden das ich ein "Aufrufende" Funktion schreiben müsste.
Wenn ich aber ehrlich bin so reicht mein Wissen an der Stelle einfach nicht aus
Wenn mir hier also jemand helfen könnte mit einer Ausführlichen Erklärung oder einem Beispiel das in meine Richtung geht wäre ich sehr dankbar.
Ich warte gespannt auf eure Antworten,
mfg
GBen
-
ich zeig dir mal, wie ich das mache
.h:
class GUIHandler { protected: virtual long OnInitDialog(WPARAM wparam, LPARAM lparam) = 0; virtual long OnCommand(WPARAM wparam, LPARAM lparam) = 0; virtual long OnNotify(WPARAM wparam, LPARAM lparam) = 0; virtual long OnClose(WPARAM wparam, LPARAM lparam) = 0; virtual long OnDestroy(WPARAM wparam, LPARAM lparam) = 0; virtual long OnSize(WPARAM wparam, LPARAM lparam) = 0; virtual long OnOwnerDraw(WPARAM wparam, LPARAM lparam) = 0; }; class GUIWindow : public GUIElement, public GUIHandler { public: GUIWindow(); GUIWindow(HINSTANCE hinst, long resid); virtual ~GUIWindow(); virtual bool New(long resid, const GUIElement *parent = NULL); long Close(); void CenterOnScreen(long xp = 0, long yp = 0) const; long IsWindow() const; long IsDialogMessage(LPMSG lpmsg) const; long EndDialog(long code) const; long SetIcon(HICON hicon, int type); HICON GetIcon(int type) const; virtual long MainLoop() const; protected: virtual long OnInitDialog(WPARAM wparam, LPARAM lparam); virtual long OnCommand(WPARAM wparam, LPARAM lparam); virtual long OnNotify(WPARAM wparam, LPARAM lparam); virtual long OnClose(WPARAM wparam, LPARAM lparam); virtual long OnDestroy(WPARAM wparam, LPARAM lparam); virtual long OnSize(WPARAM wparam, LPARAM lparam); virtual long OnOwnerDraw(WPARAM wparam, LPARAM lparam); protected: static long WINAPI WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); };.cpp
GUIWindow::GUIWindow() : GUIElement() { m_resid = 0; } GUIWindow::GUIWindow(HINSTANCE hinst, long resid) : GUIElement(hinst) { m_resid = resid; } GUIWindow::~GUIWindow() { } bool GUIWindow::New(long resid, const GUIElement *parent) { Destroy(); m_hwnd = CreateDialogParam(GetInstance(), MAKEINTRESOURCE(resid), parent ? parent->GetHandle() : NULL, reinterpret_cast<DLGPROC>(WindowProc), reinterpret_cast<LPARAM>(this)); Attach(m_hwnd); return m_hwnd != NULL; } void GUIWindow::CenterOnScreen(long xp, long yp) const { RECT rect; long xx, yy; GetWindowRect(m_hwnd, &rect); xx = GetSystemMetrics(SM_CXSCREEN); yy = GetSystemMetrics(SM_CYSCREEN); xx = (xx - (rect.right-rect.left)) >> 1; yy = (yy - (rect.bottom-rect.top)) >> 1; SetWindowPos(GUIObject(), xx+xp, yy+yp, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } long GUIWindow::EndDialog(long code) const { return ::EndDialog(GetHandle(), code); } static std::map<HWND, LPARAM> Windows; long WINAPI GUIWindow::WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { GUIWindow *gwnd = NULL; long retval = 0; switch(message) { case WM_INITDIALOG: Windows.insert(std::pair<HWND, LPARAM>(hwnd, lparam)); gwnd = reinterpret_cast<GUIWindow *>(Windows[hwnd]); gwnd->Attach(hwnd); retval = gwnd->OnInitDialog(wparam, lparam); break; case WM_COMMAND: gwnd = reinterpret_cast<GUIWindow *>(Windows[hwnd]); retval = gwnd->OnCommand(wparam, lparam); break; case WM_NOTIFY: gwnd = reinterpret_cast<GUIWindow *>(Windows[hwnd]); retval = gwnd->OnNotify(wparam, lparam); break; case WM_CLOSE: gwnd = reinterpret_cast<GUIWindow *>(Windows[hwnd]); retval = gwnd->OnClose(wparam, lparam); break; case WM_DESTROY: gwnd = reinterpret_cast<GUIWindow *>(Windows[hwnd]); retval = gwnd->OnDestroy(wparam, lparam); break; case WM_SIZE: gwnd = reinterpret_cast<GUIWindow *>(Windows[hwnd]); retval = gwnd->OnSize(wparam, lparam); break; case WM_DRAWITEM: gwnd = reinterpret_cast<GUIWindow *>(Windows[hwnd]); retval = gwnd->OnOwnerDraw(wparam, lparam); break; } return retval; } long GUIWindow::OnInitDialog(WPARAM wparam, LPARAM lparam) { return 0; } long GUIWindow::OnCommand(WPARAM wparam, LPARAM lparam) { return 0; } long GUIWindow::OnNotify(WPARAM wparam, LPARAM lparam) { return 0; } long GUIWindow::OnClose(WPARAM wparam, LPARAM lparam) { return 0; } long GUIWindow::OnDestroy(WPARAM wparam, LPARAM lparam) { return 0; } long GUIWindow::OnSize(WPARAM wparam, LPARAM lparam) { return 0; } long GUIWindow::OnOwnerDraw(WPARAM wparam, LPARAM lparam) { return 0; } long GUIWindow::IsWindow() const { if(m_hwnd) return ::IsWindow(m_hwnd); return 0; } long GUIWindow::IsDialogMessage(LPMSG lpmsg) const { if(m_hwnd) return ::IsDialogMessage(m_hwnd, lpmsg); return 0; } long GUIWindow::MainLoop() const { MSG msg; memset(&msg, 0, sizeof(msg)); while(GetMessage(&msg, NULL, 0, 0)) { if(IsWindow() && IsDialogMessage(&msg)) continue; TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } long GUIWindow::Close() { return ::CloseWindow(GetHandle()); } long GUIWindow::SetIcon(HICON hicon, int type) { return SendMessage(WM_SETICON, (WPARAM)type, (LPARAM)hicon); } HICON GUIWindow::GetIcon(int type) const { return (HICON)SendMessage(WM_GETICON, (WPARAM)type, (LPARAM)0); }Jetzt hab ich für jede Klasse, die ich von GUIWindow abgeleitet wird, nur eine einzige Callback Funktion, die dann die jeweiligen Objecte läd;
für Controls wir Buttons und so geht es ähnlich.viel spass
-
Danke esskar,
wobei WOWWOWWOW, ich fang gerade erst an mit simples Klassen geschichten und komme eigentlich aus der Java-Welt wo ableiten wirklich sehr simple ist.
Da wollte ich mich eigentlich nich gleich reinstürzen müssen, später bestimmt mal.Mir wurde von jemand anderem geraten ein reinterpret_cast zu machen.
das einzige problem hab ich ja in der Zeile:
wpOrigButtonOkProc = (WNDPROC) SetWindowLong(hWndStaticButtonOk, GWL_WNDPROC, (LONG)NewStaticProc);Weil ich LRESULT hier nicht mehr auf LONG casten konnte. Auch nicht mit einem
reinterpret_cast. Das muss mit der Kapselung zu tun haben da es ja im ersten Beispiel auch ging.Danke trotzdem esskar
PS: Du hast recht wenn du dir nun denkst das ich noch nicht so fit bin was dieses Thema angeht. Ich weiß jedoch das es auch so gehen kann wie ich mir das vorstelle, daher würde mich eine Lösung in diesem Stil sehr freun
-
LRESULT ist ein typedef auf long
zumindest irgendwann; deswegen funzt das casten nicht; static_cast hätt wohl geklapptaber callbacks in klassen müssen immer static sein; ist eben so
deklarierenstatic LRESULT CALLBACK NewStaticProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);dann musst du dir dann aber dein object in einer globalen variable speichern (oder in einer map, wie ich das gemacht habe), damit du es in der callback benutzen kannst