我们知道一个应用程序一般都不是仅仅有一个窗体组成的,往往是多窗体组成的,比方一个对话框的窗体上有一个button,这里对话框是一个窗体。button也是一个窗体。
假设一个对话框上有100个button。就是100个窗体。这样句柄会比較多。因而出现了DirectUI的设计方法,全部button和主窗体都是同一个窗体,採用分不同区域来绘画而成。这里就遇到了一个问题。每一个窗体是独立存在的,但在前面的样例里,能够看到每一个窗体都是调用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函数。由于一个窗体的消息是有非常多的,并非每一个窗体都须要处理这么多消息,因此仅仅有须要的才处理,这样处理方式是非常方便的。