分享
 
 
 

win32gui之event handling分析

王朝system·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

win32gui之event handling分析

hanlray@hotmail.com

Revision: 1.0 Date: 2005/07/17

1. 前言

win32gui是一个符合C++精神的GUI框架,源自在C++届颇有声望的cuj杂志上的一系列文章,其充分发挥了C++语言的特点,有助于提高C++在GUI开发方面的框架水平。其feature很多,现列举几个:

real GUI RAIIno more message mapseasy handling of events/ event handlingthread-safetySTL-friendly

在实际使用过程中,发现其event handling机制很独特,下面就对它进行一下分析。

2. easy handling of events

熟悉MFC,包括WTL、wxWindow开发的朋友对它们的消息映射一定不会陌生,要处理一条消息,一般需要三个步骤:

定义消息映射,把消息和消息处理函数关联起来。这一般是用某种形式的宏来实现的。在窗口类的头文件中声明该消息处理函数。在窗口类的源文件中实现该消息处理函数

虽然可能有wizard的帮助,这种过程仍然是繁琐的,也是有缺点的:

易出错。比如我想处理WM_PAINT消息,虽然我定义了ON_WM_PAINT宏,但是消息处理函数却写成了OnPaint1,这时编译器是不会 有任何错误或警告的,当然也不会调到你的这个OnPaint1函数里。换句话说,你的消息处理函数必须写得和CWnd类里定义的一模一样,如果不小心写错 了,你是不会收到任何警告的。甚至没有消息映射而只有消息处理函数,编译器也是无法发觉的。看似magic的宏的大量使用,实际上减弱了代码的可读性。增加、删除或修改消息映射通常会带来相应头文件的改变,从而增加编译时间。

win32gui是怎么做的呢?假设有一个窗口类child_view,其源文件为child_view.cpp,对其进行事件处理的步骤如下:

在child_view.cpp中定义一个负责事件处理的类,比如叫做child_view_hanlder:

struct child_view_handler : event_handler<child_view_handler, child_view> {

};

直接写消息处理函数。比如要处理的消息是WM_ERASEBKGND,就这样写:

struct child_view_handler : event_handler<child_view_handler, child_view> {

handle_event on_erase_bg(wm::draw::erase_bg_arg arg) {

...//some code here

return event<WM_ERASEBKGND>().HANDLED_BY(&me::on_erase_bg);

}

};

注意该函数名是可以任取的。

这样的过程也许不比MFC等简单多少,但其优点也是突出的:

实现对某个消息的处理只需要一个消息处理函数,而且该消息处理函数的名称是任意的,这就大大减少了出错的机会。窗口类和消息处理类是分离的,这意味改变消息处理逻辑不会影响窗口类本身。

至少从表面上看,这里是没有消息映射的,最后的那个return语句看起来有点像,但它在消息处理函数体里,总不会在执行消息处理函数的时候定义消息映射吧?当然也 不会是消息处理函数名称,因为它的名称是任取的。就算win32gui对Win32 GUI封装的再好,也不可能脱离win32窗口系统的原理:系统肯定会向这个 child_view窗口发送一条WM_ERASEBKGND消息,要对该消息进行处理,是一定需要该消息与消息处理函数的对应关系的,不管该关系用什么方式表达。 其实关键就是在那个return语句上,它显然可以是一种消息映射的表达,只是位置有点奇怪而已。其中的HANDLED_BY是一个宏,其定义为

#define HANDLED_BY(f) get_proxy(f).handled_by<f>()

先看event类模板的定义:

template<int wm> struct event {

template<class self_type>

detail::event_keeper0<wm,self_type> get_proxy( handle_event (self_type::*)() ) {

return detail::event_keeper0<wm,self_type>();

}

template<class self_type, class p1>

detail::event_keeper1<wm,self_type,p1> get_proxy( handle_event (self_type::*)(p1) ) {

return detail::event_keeper1<wm,self_type,p1>();

}

template<class self_type, class p1, class p2>

detail::event_keeper2<wm,self_type,p1,p2> get_proxy( handle_event (self_type::*)(p1,p2) ) {

return detail::event_keeper2<wm,self_type,p1,p2>();

}

template<class self_type, class p1, class p2, class p3>

detail::event_keeper3<wm,self_type,p1,p2,p3> get_proxy( handle_event (self_type::*)(p1,p2,p3) ) {

return detail::event_keeper3<wm,self_type,p1,p2,p3>();

}

template<class self_type, class p1, class p2, class p3, class p4>

detail::event_keeper4<wm,self_type,p1,p2,p3,p4> get_proxy( handle_event (self_type::*)(p1,p2,p3,p4) ) {

return detail::event_keeper4<wm,self_type,p1,p2,p3,p4>();

}

template<class self_type, class p1, class p2, class p3, class p4, class p5>

detail::event_keeper5<wm,self_type,p1,p2,p3,p4,p5> get_proxy( handle_event (self_type::*)(p1,p2,p3,p4,p5) ) {

return detail::event_keeper5<wm,self_type,p1,p2,p3,p4,p5>();

}

template<class self_type, class p1, class p2, class p3, class p4, class p5, class p6>

detail::event_keeper6<wm,self_type,p1,p2,p3,p4,p5,p6> get_proxy( handle_event (self_type::*)(p1,p2,p3,p4,p5,p6) ) {

return detail::event_keeper6<wm,self_type,p1,p2,p3,p4,p5,p6>();

}

};

其有多个成员含函数模板,分别对应消息处理函数的参数个数从0到6的情况。这里我们的消息处理函数只需要一个参数,因此get_proxy返回的是实例属于 detail::event_keeper1类模板,再看event_keeper1的定义:

template<int wm, class me, class p1> struct event_keeper1 {

template<handle_event (me::*func)(p1)> handle_event handled_by() {

return event_adder<wm, me, func1_caller<me,p1,func> >();

}

};

其返回的是event_adder类模板的实例:

template<int wm, class me, class func> struct event_adder : handle_event {

event_adder() {

if ( detail::initialize_static_trick() ) {

assert(false); // should never happen

s_adder = event_adder_impl<wm,me,func>();

}

}

static event_adder_impl<wm,me,func> s_adder;

};

可以看到,event_adder的构造函数好像也没做什么,关键在于s_adder这个static成员上,看看其类型定义:

template<int wm, class me, class func> struct event_adder_impl : register_possible_dialog<me> {

typedef typename func::first_arg first_arg;

event_adder_impl() {

WIN32GUI_LOG("adding event " << wm << " for " << typeid(me).name());

if ( initialize_static_trick() ) {

// force the compiler to generate the constructor for the 'me' class

new me;

// v1.5+

// extra safety for the first argument...

typedef typename ignore_enhanced_msg<first_arg>::arg func_first_arg;

int first_argument_and_return_DONOT_match_please_check_again = check_event<wm,func_first_arg>( (func_first_arg*)0);

}

// note: for the same message, we might have multiple functions

me::s_events()[ (UINT)wm].push_back( &func::call );

}

};

真相大白了!最后一句清楚地表明,这里是有消息映射的!实际上win32gui对于每个event handler类型,在内部都为其维护了一个消息映射表,使用的数据结构是stl::map。消息处理函数的return语句在运行时实际什么也没做,它的存在只是为了让编译器产生event_adder_impl的静态变量,在这些 静态变量的初始化时刻,其构造函数被调用,从而建立消息映射关系。

3. 结束语

虽然win32gui号称no more message maps,但从上分析,其还是存在消息映射的,这也是由win32窗口系统本身决定的;只不过其表达方式有些特别,利用了模板和静态变量技术,较之MFC之类的方式,其优点也是相当明显的。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有