我们知道一个应用程序一般都不是只有一个窗口组成的,往往是多窗口组成的,比如一个对话框的窗口上有一个按钮,这里对话框是一个窗口,按钮也是一个窗口。如果一个对话框上有100个按钮,就是100个窗口,这样句柄会比较多。因而出现了DirectUI的设计方法,所有按钮和主窗口都是同一个窗口,采用分不同区域来绘画而成。这里就遇到了一个问题,每个窗口是独立存在的,但在前面的例子里,可以看到每个窗口都是调用PyWndProc函数来处理。意味着多个窗口的消息都抛给PyWndProc函数处理,这样处理起来只会越来越多,越来越复杂。站在面向对象设计角度来考虑,是否可以有一个更好的方案解决呢?这个是可以的,由于Windows里给每个窗口保留了一个用户数据字段,只要利用这个字段,就可以关联起每个窗口与消息类之间的关系。比如窗口1就调用窗口1的类来处理消息,窗口2就调用窗口2的类来处理消息,这样每个窗口的独立性就得到保障,不用担心窗口1的消息会跑到窗口2去。为此,我声明了一个类Controller,用这个类来处理窗口的消息,当然不同的窗口都可以继承这个类,而实现其它的窗口消息处理。创建类Controller的实例之后,把这个实例对象保存到窗口的GWL_USERDATA字段里。参考《Windows API一日一练》介绍创建窗口的函数,如下:
HWND CreateWindowEx(
DWORD dwExStyle,//窗口的扩展风格
LPCTSTR lpClassName,//指向注册类名的指针
LPCTSTR lpWindowName,//指向窗口名称的指针
DWORD dwStyle,//窗口风格
int x,//窗口的水平位置
int y,//窗口的垂直位置
int nWidth,//窗口的宽度
int nHeight,//窗口的高度
HWND hWndParent,//父窗口的句柄
HMENU hMenu,//菜单的句柄或是子窗口的标识符
HINSTANCE hInstance,//应用程序实例的句柄
LPVOID lpParam//指向窗口的创建数据
);
在这个API函数的最后字段lpParam,就是指向窗口用户自定义的数据,在这里,我把消息处理类对象的指针放到这里,就可以让每个窗口有自己的消息处理类了。
定义类Controller如下:
class Controller: def __init__(self): self.hWnd = HWND() def SetWnd(self, hWnd): self.hWnd = hWnd def MyWndProc(self, hWnd, Msg, wParam, lParam): if Msg == WM_DESTROY: windll.user32.PostQuitMessage(0) return 0 else: return windll.user32.DefWindowProcW(hWnd, Msg, wParam, lParam)
在类Controller里,主要有成员变量self.hWnd,它是用来保存每个窗口的句柄;成员函数MyWndProc是用来处理每个窗口的消息,如果窗口没有处理,就会把这些消息传递给Windows系统默认处理,而这个处理默认消息的函数是DefWindowProcW函数。因为一个窗口的消息是有很多的,并不是每个窗口都需要处理这么多消息,因此只有需要的才处理,这样处理方式是非常方便的。