【发布时间】:2013-07-09 03:41:18
【问题描述】:
我将自定义窗口封装在一个带有静态 WndProc 函数的类中,以处理由它生成的消息。现在我有一个子类,它在消息处理过程中实现了与父类不同的一些功能。
例如在下面的代码中,子类中 WM_LBUTTONDOWN 中发生的情况与父类中发生的情况不同。
我考虑过多态性,但我认为它不起作用,因为从父类调用 ::SetWindowLongPtr() 并且传递给的“this”指针属于父类,如果我错了,请纠正我。
如果我错了,多态性在这种情况下会起作用,那么也有一些消息没有被父类处理,应该在子类中处理,并为此在父类中放置一个空的虚函数看起来并不干净,除了很难为窗口产生的每条消息放置一个空的虚函数,只是为了将来是否会被使用。
会有几个这样的子类,每个子类对某些消息的行为不同,但不是全部。
那么,我该怎么做呢。
parent.cpp
parent::parent()
{
WNDCLASSEX wincl;
wincl.hInstance = hInstance;
wincl.lpszClassName = "parent";
wincl.lpfnWndProc = WndProc;
wincl.style = CS_BYTEALIGNWINDOW;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = 0;
wincl.hIconSm = 0;
wincl.hCursor = ::LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 4;
wincl.hbrBackground = ::CreateSolidBrush( backgroundColor );
::RegisterClassEx ( &wincl );
hwnd = ::CreateWindowEx ( 0, "parent", txt.c_str(), WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD, x, y, width, height, parent, 0, hInstance, 0 ) ;
::SetWindowLongPtr( hwnd , GWLP_USERDATA , ( LONG ) this ) ;
}
LRESULT CALLBACK parent::WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
view::parent* panel = reinterpret_cast < view::parent* > ( ::GetWindowLongPtr ( hwnd , GWLP_USERDATA ) );
switch (message)
{
case WM_CREATE:
::SendMessage ( hwnd, WM_SETFONT, ( WPARAM ) panel->hFont, ( LPARAM ) true );
break ;
case WM_COMMAND:
return panel->command ( message, wParam, lParam );
break ;
case WM_LBUTTONDOWN:
return panel->lButton ( message, wParam, lParam );
break;
case WM_RBUTTONDOWN:
return panel->rButton ( message, wParam, lParam );
break;
case WM_ERASEBKGND:
return 1;
break;
case WM_PAINT:
return panel->paint ( );
break ;
default:
return ::DefWindowProc (hwnd, message, wParam, lParam);
}
return 0 ;
};
谢谢。
【问题讨论】:
-
一种常见的方法是创建虚拟或纯虚拟成员函数,例如
virtual LRESULT onButtonDown(...) {}等 -
@JoshGreifer 所以你是说多态性在这种情况下会起作用,即使传递给 ::SetWindowLongPtr() 的“this”指针属于父类?
-
使
parent::WndProc虚拟化。派生类覆盖child::WndProc,处理他们想要覆盖的消息,对于那些他们不想覆盖的消息,将调用转发到parent::WndProc。 This is a standard technique. -
@StudentX:您的 WndProc 需要在使用之前检查
panel是否为 NULL。WM_CREATE不是窗口接收的第一条消息,并且窗口在CreateWindowEx()退出之前,在您的代码调用SetWindowLongPtr()之前接收消息。更安全一点的方法是将this指针传递给CreateWindowEx(),然后在WM_CREATE处理程序中调用SetWindowLongPtr()。不过,您仍然需要考虑在WM_CREATE之前收到的消息。 -
当对某些东西的工作方式有疑问时(在本例中为虚拟调度和
this指针),您应该编写一个简单的测试程序,检查它的执行情况并了解它是如何工作的。不要一直猜测。