当前位置:编程学习 > asp >>

WinForm二三事(一)补遗

在WinForm二三事(一)里,我们谈了WinForm上的事件(比如点击啊,双击啊)是借助消息循环,消息分发的机制实现的。但那篇里只是一笔带过。后来有人问我这中间的具体关系是什么呢?那今天我们就来详细谈谈从Win32的Message到WinForm上的 Event。

Win32中的Hello world
要具体了解这个问题,我们先来看看在Win32的时候,使用原生的API(或者叫Native API)如何做个简单的Hello World的小窗体:

   1: #include <windows.h>
   2: 
   3: //这就是就受消息,然后处理的地方了
   4: LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
   5: {
   6:     switch(msg)
   7:     {
   8:         case WM_DESTROY:PostQuitMessage(0);return 0;
   9:         default:return DefWindowProc(hwnd,msg,wparam,lparam);
  10:     }
  11: }
  12: 
  13: int WINAPI WinMain(HINSTANCE instance,HINSTANCE prev,LPSTR cmdLine,int cmdShow)
  14: {
  15:     //一个窗体类,用来设置窗体的各种属性,比如大小啊、背景颜色啊等等
  16:     WNDCLASSEX windowClass;
  17:     MSG msg;
  18:     HWND window;
  19:     memset(&windowClass,0,sizeof(WNDCLASSEX));
  20:     windowClass.cbSize = sizeof(WNDCLASSEX);
  21:     windowClass.hInstance = instance;
  22:     windowClass.lpszClassName = "HelloWorld";
  23:     //注意这里,当消息分发到这个窗体上来的时候,就是由WndProc这个函数进行处理
  24:     windowClass.lpfnWndProc = WndProc;
  25:     windowClass.hbrBackground = (HBRUSH)COLOR_WINDOW+1;
  26:    
  27:     if(!RegisterClassEx(&windowClass))
  28:     {
  29:         MessageBox(NULL,"不能注册窗体类","",MB_OK|MB_ICONERROR);
  30:         return 1;
  31:     }
  32:     window = CreateWindowEx(0,"MainWnd","Hello World",WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
  33:                 CW_USEDEFAULT, CW_USEDEFAULT, 200, 150, NULL, NULL, instance, NULL);
  34:     ShowWindow(window,cmbShow);
  35:    
  36:     //消息循环,从消息队列里获取消息,然后分发消息
  37:     //实际上GetMessage方法会返回-1(意思是出错了),所以下面这样的写法并不总是正确的
  38:     while(GetMessage(&msg,NULL,0,0))
  39:     {
  40:         TranslateMessage(&msg);
  41:         DispatchMessage(&msg);
  42:     }
  43:    
  44:     return 0;
  45: }

啊,在Win32的时候,要弹出一个空白窗口就要干这么多事儿啊。仔细看看上面的代码,不去深究Win32底层的细节,我们可以这么理解:GetMessage从当前线程的消息队列上获取一条消息(什么是消息?鼠标在窗体上点击一下,键盘的案件按下,窗体创建了,窗体开始绘制,窗体销毁这都是消息,这些消息会一个个的发送到一个消息队列中),然后TranslateMessage负责转换这个消息(意思就是将原生的消息,转换成“好懂”的消息,比如你按个F1,它将其转换为WM_HELP消息),然后DispatchMessage就是分发这个消息,发到哪里呢?就是上面的WndProc函数,WndProc函数接收到消息后,里面有个switch,switch根据消息的类型来决定干什么,比如接收到一个按钮点击然后调用按钮点击的调用函数。整个过程就像一个流水线一样,按部就班的执行。

ok,对Win32的讨论到此为止,我们再回到.Net。我们来看看在.Net里如何编写一个窗体呢?

WinForm中的Hello world
   1: public class HelloWorld:Form
   2: {
   3:     public HelloWorld()
   4:     {
   5:         InitializeComponent();
   6:     }
   7:    
   8:     private void InitializeComponent()
   9:     {
  10:         //这里是不是很像Win32中对WNDCLASSEX的设置?
  11:         this.Size = new Size(300,200);
  12:        this.Text = "Hello World";
  13:        this.Name = "HelloWorld";
  14: 
  15:        this.Click += new System.EventHandler(helloworld_Click);
  16:     }
  17: 
  18:     private void helloworld_Click(object sender,EventArgs e)
  19:    {
  20:        MessageBox.Show("窗体点击了");    
  21:    }
  22: }

Message与Event的连接
哦,.Net的代码,我们不仅仅实现了一个空白的窗体,还附加了一个点击窗体时的事件,可代码简洁的多,也没有很多的细节。看似这个与Win32的有点联系,又没有联系,这个点击窗体的事件到底是怎么触发的呢?我们一直追索Form的继承层次,发现Form是间接的从Control派生的,而Control类里发现了一个WndProc方法:

   1: protected virtual void WndProc(ref Message m)
   2: {
   3:     if ((this.controlStyle & ControlStyles.EnableNotifyMessage) == ControlStyles.EnableNotifyMessage)
   4:     {
   5:         this.OnNotifyMessage(m);
   6:     }
   7:     switch (m.Msg)
   8:     {
   9:         case 1:
  10:             this.WmCreate(ref m);
  11:             return;
  12:         //............
  13: 
  14:         case 8:
  15:             this.WmKillFocus(ref m);
  16:             return;
  17:         case 0x200:
  18:             this.WmMouseMove(ref m);
  19:             return;
  20:    
  21:         case 0x201:
  22:             this.WmMouseDown(ref m, MouseButtons.Left, 1);
  23:             return;
  24:    
  25:         case 0x202:
  26:             this.WmMouseUp(ref m, MouseButtons.Left, 1);
  27:           

补充:Web开发 , ASP.Net ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,