下面是一个完整的程序,它示范了在派生类中WM_PAINT消息的使用。
程序70.
#include <windows.h>
class ZWindow;
ZWindow* g_pWnd = NULL;
class ZWindow { public: HWND m_hWnd;
ZWindow(HWND hWnd = 0) : m_hWnd(hWnd) { }
inline void Attach(HWND hWnd) { m_hWnd = hWnd; }
inline BOOL ShowWindow(int nCmdShow) { return ::ShowWindow(m_hWnd, nCmdShow); }
inline BOOL UpdateWindow() { return ::UpdateWindow(m_hWnd); }
inline HDC BeginPaint(LPPAINTSTRUCT ps) { return ::BeginPaint(m_hWnd, ps); }
inline BOOL EndPaint(LPPAINTSTRUCT ps) { return ::EndPaint(m_hWnd, ps); }
inline BOOL GetClientRect(LPRECT rect) { return ::GetClientRect(m_hWnd, rect); }
BOOL Create(LPCTSTR szClassName, LPCTSTR szTitle, HINSTANCE hInstance, HWND hWndParent = 0, DWORD dwStyle = WS_OVERLAPPEDWINDOW, DWORD dwExStyle = 0, HMENU hMenu = 0) { m_hWnd = ::CreateWindowEx(dwExStyle, szClassName, szTitle, dwStyle, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWndParent, hMenu, hInstance, NULL); return m_hWnd != NULL; }
virtual LRESULT OnPaint(WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; RECT rect;
hDC = BeginPaint(&ps); GetClientRect(&rect); ::DrawText(hDC, "Hello world", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(&ps); return 0; }
virtual LRESULT OnCreate(WPARAM wParam, LPARAM lParam) { return 0; }
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ZWindow* pThis = g_pWnd;
switch (uMsg) { case WM_CREATE: pThis->OnCreate(wParam, lParam); break;
case WM_PAINT: pThis->OnPaint(wParam, lParam); break;
case WM_DESTROY: ::PostQuitMessage(0); break; } return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } };
class ZDriveWindow : public ZWindow { public: LRESULT OnPaint(WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; RECT rect;
hDC = BeginPaint(&ps); GetClientRect(&rect); SetBkMode(hDC, TRANSPARENT); DrawText(hDC, "Hello world From Drive", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(&ps);
return 0; } }; |
程序的输出是一个窗口中的一条“Hello world from Drive”消息。在我们使用派生类之前,可以说一切都是顺利的。当我们从ZWindow派生出多于一个类的时候,问题就会发生。这样,所有的消息就都会流向ZWindow最后继承的那个派生类。让我们看看以下的程序。
程序71.
#include <windows.h>
class ZWindow;
ZWindow* g_pWnd = NULL;
class ZWindow { public: HWND m_hWnd;
ZWindow(HWND hWnd = 0) : m_hWnd(hWnd) { }
inline void Attach(HWND hWnd) { m_hWnd = hWnd; }
inline BOOL ShowWindow(int nCmdShow) { return ::ShowWindow(m_hWnd, nCmdShow); }
inline BOOL UpdateWindow() { return ::UpdateWindow(m_hWnd); }
inline HDC BeginPaint(LPPAINTSTRUCT ps) { return ::BeginPaint(m_hWnd, ps); }
inline BOOL EndPaint(LPPAINTSTRUCT ps) { return ::EndPaint(m_hWnd, ps); }
inline BOOL GetClientRect(LPRECT rect) { return ::GetClientRect(m_hWnd, rect); }
BOOL Create(LPCTSTR szClassName, LPCTSTR szTitle, HINSTANCE hInstance, HWND hWndParent = 0, DWORD dwStyle = WS_OVERLAPPEDWINDOW, DWORD dwExStyle = 0, HMENU hMenu = 0, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int nWidth = CW_USEDEFAULT, int nHeight = CW_USEDEFAULT) { m_hWnd = ::CreateWindowEx(dwExStyle, szClassName, szTitle, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, NULL); return m_hWnd != NULL; }
virtual LRESULT OnPaint(WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; RECT rect;
hDC = BeginPaint(&ps); GetClientRect(&rect); ::DrawText(hDC, "Hello world", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(&ps); return 0; }
virtual LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam) { return 0; }
virtual LRESULT OnCreate(WPARAM wParam, LPARAM lParam) { return 0; }
virtual LRESULT OnKeyDown(WPARAM wParam, LPARAM lParam) { return 0; }
static LRESULT CALLBACK StartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ZWindow* pThis = g_pWnd;
if (uMsg == WM_NCDESTROY) ::PostQuitMessage(0);
switch (uMsg) { case WM_CREATE: pThis->OnCreate(wParam, lParam); break;
case WM_PAINT: pThis->OnPaint(wParam, lParam); break;
case WM_LBUTTONDOWN: pThis->OnLButtonDown(wParam, lParam); break;
case WM_KEYDOWN: pThis->OnKeyDown(wParam, lParam); break;
case WM_DESTROY: ::PostQuitMessage(0); break; }
return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } };
class ZDriveWindow1 : public ZWindow { public: LRESULT OnPaint(WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; RECT rect;
hDC = BeginPaint(&ps); GetClientRect(&rect); ::SetBkMode(hDC, TRANSPARENT); ::DrawText(hDC, "ZDriveWindow1", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(&ps);
return 0; }
LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam) { ::MessageBox(NULL, "ZDriveWindow1::OnLButtonDown", "Msg", MB_OK); return 0; } };
class ZDriveWindow2 : public ZWindow { public: LRESULT OnPaint(WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; RECT rect;
hDC = BeginPaint(&ps); GetClientRect(&rect); ::SetBkMode(hDC, TRANSPARENT); ::Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom); ::DrawText(hDC, "ZDriveWindow2", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(&ps);
return 0; }
LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam) { ::MessageBox(NULL, "ZDriveWindow2::OnLButtonDown", "Msg", MB_OK); return 0; } };
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { char szAppName[] = "Hello world"; MSG msg; WNDCLASS wnd; ZDriveWindow1 zwnd1; ZDriveWindow2 zwnd2;
wnd.cbClsExtra = NULL; wnd.cbWndExtra = NULL; wnd.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); wnd.hCursor = LoadCursor(NULL, IDC_ARROW); wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); wnd.hInstance = hInstance; wnd.lpfnWndProc = ZWindow::StartWndProc; wnd.lpszClassName = szAppName; wnd.lpszMenuName = NULL; wnd.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClass(&wnd)) { MessageBox(NULL, "Can not register window class", "Error", MB_OK | MB_ICONINFORMATION); return -1; }
g_pWnd = &zwnd1; zwnd1.Create(szAppName, "Hell world", hInstance);
zwnd1.ShowWindow(nCmdShow); zwnd1.UpdateWindow();
g_pWnd = &zwnd2;
zwnd2.Create(szAppName, "Hello world", hInstance, zwnd1.m_hWnd, WS_VISIBLE | WS_CHILD | ES_MULTILINE, NULL, NULL, 0, 0, 150, 150);
while (GetMessage(&msg, NULL, 0, 0)) { DispatchMessage(&msg); } return msg.wParam; } |
程序的输出表明,不管你单击了哪个窗口,都会弹出相同的MessageBox。
不管你单击了哪个窗口,你都会获得相同的消息框。这就意味着消息并没有传递给适当的窗口。事实上每个窗口都拥有自己的窗口过程,这些窗口过程处理窗口的所有消息。但是在这里,我们对第一个窗口使用了第二个窗口的回调函数,所以我们就不能对第一个窗口的消息进行处理了。
现在,我们最主要的问题是将窗口的回调函数和相应的窗口关联起来。这就意味着HWND应该和相应的派生类关联起来,所以消息应该发送给正确的窗口。解决这个问题可以有若干种方法,让我们来一个一个看一看。
|