`
lovnet
  • 浏览: 6693547 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

C++与C#对比学习:消息,事件(一)

 
阅读更多

窗体(windows),事件(event),消息(message)

我们大部分人用的操作系统都是微软的windows系列.windows顾名思义是窗口,窗体.它最大的特点就是几乎所有操作都是图形界面.在面向对象开发中是一切皆对象,那在windows的操作中是一切皆窗体.窗体背后对应的是消息机制.是以消息以基础,以事件为驱动.所谓窗体就是我们能用眼睛看得到的一个个图形界面,几乎任何可显示的实体都是窗口,有时弹出的对话框也算个小窗体,一个按钮也算窗体.一个界面可以由多个窗体组合而成.事件就代表着所有的操作,比如鼠标动一下,点一下,窗口拉大拉小,文本框输入文字等...而事件发生后是以消息的形式发给应用程序对应的函数去处理.所以窗体,事件,消息三者的关系是我们对窗体的操作就是一个事件,事件会产生消息.

windows操作系统是事件驱动,那运行在它上面的绝大部分应用程序自然也是事件驱动.应用程序大部分时候是傻傻的呆那不动的,只有你去点下它才会动起来,做相应的操作.当然了有些应用程序可能会有些后台操作,比如设个时钟,每过多久自动刷新下或做些其他啥操作.

我觉得人其实也有点像个事件驱动的机器了.我们接受各种内部或外部的刺激,然后产生各种反应.就算在睡觉时也在接受刺激做些本能的反应.行为主义心理学派就认为人根本没有所谓的自由意志,就只知道通过一些刺激做些反应.只不过各种刺激非常复杂,并且反应也是一系列的连锁反应,所以我们不容易感觉的到.当然各大 心理学派所持的观点不一样,那些理论我们也不容易证否.跟算法里面著名的NP难问题有点类似,我们不知道NP难问题是不是能解决.不能证明它能解决,也不能证明它不能解决.

消息控件一般分三层结构.

第一层,windows内核.里面维护一个消息队列,像鼠标,键盘等一些IO设备产生事件后不是直接传给应用程序,而是先被操作系统处理,转换成一个个的"消息".由于创建窗体时会指定一个应用程序句柄,所以当操作某个窗体产生时操作系统知道哪些消息是属于哪个应用程序的,操作系统为每个应用程序维护一个消息队列.

第二层,应用程序.在windows API的编程中一般通过一个while循环,用GetMessage或PeekMessage来获取消息队列中的消息.不过这些信息还只相当于是原材料,需要进一步加工.通过TranslateMessage把它进一步加工,做一些转换,或者如果是些无用的消息就会被直接忽略掉.加工完了后又通过DispatchMessage把信息重新传回操作系统.每一个消息实际上是一个一个结构体,里面有些相关信息,里面有一个窗体句柄.这样我们就知道这个消息是哪个窗体产生的.

第三层,窗体过程(windows procedure),创建窗体时会指定一个窗体过程,实际上就是窗体对应的一些处理消息的函数.当应用程序把消息重新传回操作系统后.操作系统再把消息发送给窗口过程,窗口过程就根据消息中的一些信息做些判断做些不同的处理.

C#中的事件处理机制

在C#中做了很多的封装,我们根本看不到消息的处理过程.通过层层封装最后我们看到的只是事件(event)这个概念,在C#中event是个关键字,也可以看做某种类型.当对窗体做一些操作时可以生成一个个的事件.比如点击按键btnOK,它对应的事件是btnOK.Click.(Click是C#中事先定义好了的事件,我们只要拿来用就行.)其实我们可以这样简单的理解,消息控制的三层结构中,前面所有操作都给你封装了,直到最后指定一个个的窗体过程,而且不同的消息对应的窗体过程都指定好的了.只不过那个过程为空,有点相当于个函数指针,要你自己去指定一个具体的函数.在C#中没有指针,但有个概念叫代理(delegate),它类似于函数指针.而事件相当于是对代理的封装,或者说是代理的一种应用.代理还可以用在其他很多地方.

(补充:我后面在类System.Windows.Forms.NativeWindow中发现有这样的函数,

protected virtual void WndProc(ref Message m);//用户自定义窗口过程,你看名字和C++中的都一样

public void DefWndProc(ref Message m);//默认窗口过程

所以C#中的事件处理机制原理各C++中完全一样的.只不过做了很多封装了.估计用户指定一个一个事件对应的处理函数时就和WndProc绑定一起了.不过里面具体怎么操作就不清楚了,被微软封装了找起来特别麻烦.)

比如定义事件Click是这样定义的.

(1)public event EventHandler Click;// 其中EventHandler是一个代理类型.定义事件的规范格式就是用关键字event然后加代理类型,然后再加变量名.定义代理EventHandler的格式是这样的.

(2)public delegate void EventHandler(object sender, EventArgs e);//它表示EventHandler可以指向任意以object,EventArgs为参数,返回类型是void的函数.我们前面说了事件Click还只相当于一个空的窗体过程.那我们怎么去指定具体的函数来.我们可以通过+=这样的关键字来指定一个事件处理程序.比如

(3)btnOK.Click += new System.EventHandler(btnOK_Click); //其中btnOK_Click是函数名,你也可以取其他任何名字.然后在class中任何地方定义函数

而且绑定多个像+=添加字符串一样直添加.当一个事件绑定了多个函数时,事件触发时多个函数会全部执行.当然我们还能通过-=这样的关键字解除某个函数的绑定.

void btnOK_Click(object sender, EventArgs e)

{

//操作相应操作的代码

}

反正C#中所有与窗口或控件相关的事件都给你封装好了,你直接拿来用,只要绑定个具体的函数就行.另外事件绑定的函数类型一般是两个参数,其中第一个是object sender,它表明是哪个窗体对象触发的这个事件.如果是按钮的话可以把把这个object对象转换成button对象,然后获取按钮其他信息(button)sender.另外一个参数是EventArgs,其实这个参数有时会不一样,如果是键盘触发的事件它就是KeyPressEventArgs了,它是附带有其他一些信息,比如键盘按的哪个按钮啊.

不过实际上我们也很少用到这两参数,让它们摆在那不管,自己在函数中写其他代码就行了.

自定义事件

另外除了预定义好的事件可以直接拿来用外,我们还可以自己定义些事件,使用的语法格式完全一样.自已定义的事件不一定得是窗体事件,可以是其他任何东东.比如某个变量值达到多少时触发个事件之类的。

自定义的事件具体是怎么触发它执行的由于已经封装了我们也看不到.不过如果是自定义事件肯定得指定怎么去执行.举个简单的例子看下吧.

public delegate void SayHello(string str); //声明一个代理

public event SayHello onSayHello; //定义一个事件onSayHello

触发事件执行的代码就是

stringmsg = "arwen";

onSayHello(msg); //看起来跟调用一个函数没啥区别了.当然你调用它之前还得先绑定一个函数给它,不然会出错的.所以一般用if(onSayHello != null)这样判断一下,如果事件还没绑定啥函数上去就为null

那既然事件都跟调用函数都差不多了,还不如直接调用函数或者调用代理,为啥搞得多此一举,再整个事件来啊.

用自定义事件可能基于两种原因吧,当然这是我自己瞎猜的啊

一,是体现一种设计模式,订阅者模式.

二,是当体现封装原则.

比如一个class想调用另外一个class中某个函数时,不想让直接调用,或者函数声明为private的,就可通过event间接的调用.因为delegate相当于指向函数的指针,而event又相当于是对delegate的封装.那你可能又问封装有啥好的啊,这可能是体现一种设计思想,对以后扩充功能或做一些额外的处理有用吧.不然像像我们把所以类中的字段都给封装成一个个的属性(property),大部分时候是一点都看不出来有啥用,反而觉得有点多此一举,还不如直接用字段别用属性呢.但如果我们有时想在属性中做些额外的处理时特别有用.比如只让你读取字段值不让赋值,或者反过来.

举个用自定义事件调用其他类中的private函数的简单例子吧.

在class A中有private的函数sayHello.那class B中肯定不能直接调用sayHello了.当然我们另外还要假设在A中用到了B.

delegate void DelegateSayHello(string name); //在类外面某个地方,它其实也可以看成一种特殊的类了.当然也可以放在某个类里面定义

public class A

{

B sb;

sb.HowAreYou += new DelegateSayHello(sayHello);

private void sayHello(string name)

{

Console.WriteLine("Hello," + name);

}

}

public class B

{

public event DelegateSayHello HowAreYou;

string name = "arwen";

private void DoSomething()

{

HowAreYou(name); //这里就调用了class A中的private函数sayHello了啊

}

}

分享到:
评论

相关推荐

    C++与C#的一些比较

    C++与C#的一些比较,适合学习者。为您提供这两种语言的最重要差异。

    通过C++的类比较来学习C#的类的使用

    在 C#中,类的定义方式和C++中基本一致,但是在调用的类的时候,必须注意C#中的类属 于引用类型的变量。当定义一个类的变量之后,必须要先用new 对该引用实例化,然后才 可以进行初始化等工作。所以用惯了C++的...

    C#教程 讲得很详细 对比c++ 有助于有c++基础的人学习

    本章介绍C#语言的基础知识,希望具有C语言的读者能够基本掌握C#语言,并以此为基础,能够进一步学习用C#语言编写window应用程序和Web应用程序

    C++程序员快速学习C#

    随着.NET的深入人心,作为一个程序员,当然不能在新技术面前停而止步,面对着c++在.net中的失败,虽然有一丝遗憾,但是我们应该认识到,对于c++其实就不应该对其在.net中的表现有太大的奢望,...这样的对比学习可以让我们在

    C#和JAVA的比较

    C#(C-Sharp)是Microsoft的新编程语言,被誉为“C/C++家族中第一种面向组件的语言”。然而,不管它自己宣称的是什么,许多人认为C#更像是Java的一种克隆,或者是Microsoft用来替代Java的产品。事实是否是这样的呢?...

    C#版的数据结构教程

    C#版的数据结构(英语教材),可以用来对比C/C++版的数据结构学习!

    iOS 13下的系统颜色,将颜色对比显示,便于设计挑选查看。.zip

    软件开发设计:PHP、QT、应用软件开发、系统软件开发、移动应用开发、网站开发C++、Java、python、web、C#等语言的项目开发与学习资料 硬件与设备:单片机、EDA、proteus、RTOS、包括计算机硬件、服务器、网络设备、...

    vc++ 开发实例源码包

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    《软件系统架构与开发环境》第二章源代码-by 南邮-陈杨

    2.2 C++与Java的对比综述 60 2.3 C++与Java的开发工具与开发过程 67 2.3.1 C++的基本开发工具与开发过程 67 2.3.2 Visual C++的开发平台与开发过程 70 2.3.3 Java的基本开发工具与开发过程 72 2.3.4 Java的三...

    利用pyQt5完成的GUI简易的图像编辑器,包括滤镜,亮度对比度锐化处理,旋转翻转,更改图片尺寸等操作.zip

    包括C++、Java、python、web、C#、EDA等项目的源码。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的...

    毕设&课设&项目&实训-基于selenium的web端UI测试框架,另外支持简单的图片对比功能.zip

    包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】...

    vc++ 应用源码包_6

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    1.对模糊车牌图像进行清晰处理;2.对高斯模糊图像进行高斯平滑滤波处理;4.对雾化图像进行直方图均衡化处理;

    包括C++、Java、python、web、C#、EDA等项目的源码。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的...

    OpenCV识别出两张图片的人脸,并比较出两张人脸的相似度,并给出相似值(包含完整的工程!!)

    OpenCV识别出两张图片的人脸,并比较出两张人脸的相似度,并给出相似值。 包含完整的工程文件,可立即运行!!! 用facedetect功能将两张图片中的人脸检测出来 将人脸部分的图片剪切出来,存到两张只有人脸的图片...

    读入手写数字图片进行归一化处理,统一尺寸.zip

    包括C++、Java、python、web、C#、EDA等项目的源码。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的...

    vc++ 应用源码包_1

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_2

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_3

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_5

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

Global site tag (gtag.js) - Google Analytics