Win32API界面库 - Project wheels 工程基础部分完成
离上次发博文过去了好久,先是要忙一个机器人的项目,然后就是部门的事情和考试周复习,然后就到了考试周,趁着复习的间隙,拾起了寒假时候抄的界面库,修掉了从前的bug。
bug1 控件显示问题
当初抄这个库的时候就对排版部分的代码一头雾水,借着这次调bug,稍微理清了排版部分代码的意图。界面的排版是动态进行的,用户用placement命名空间的各种排版元素构造出整个排版的结构布局,然后调用WinForm对象的ApplyPlacement成员,把前面构造好的布局传给它,函数内部递归地读取结构对象的大小和它的子对象,一层一层的计算并应用排版布局。
如此应用排版
ApplyPlacement(
HorzScale(10, 100, 0.5,
Control(txtRegex),
Control(txtRegex2)
)
);
ApplyPlacement里面是单纯的调用的排版对象的ApplyTo函数
inline
void WinContainer::ApplyPlacement(placement::Base::Pointer Placement)
{
Placement->ApplyTo(GetPlacement());
}
ApplyTo函数是个虚函数,根据不同的排版元素,有不同的效果,基本原理上都是计算空间,设定当前布局在窗口大小变化时的行为,递归应用子元素的排版,然后设定子元素的位置。
feature2 修改了Event的定义
这个库原版的事件是用宏来批量生成的,代码没有高亮,夹杂着各种连接token的##,显得十分晦涩难懂,不过考虑到这个库是vczh大学时期的作品,那时候还没有C++11,不能愉快的使用变长模板参数来写一个Event,选择用宏来替代也是一个不错的选择,阅读代码的人面对着这一大片宏,肯定会先感叹编写者的牛b吧。
这一次把Event替换成了vlpp里面的Event,并且由于连带的包含关系,我把智能指针类Ptr和函数对象类Func也一并抄了过来。综合对比这个库之前的Event和vlpp里的Event,两者在代码的组织上并没有太大的区别,只是vlpp条理更加清晰,把EventHandler的部分独立出来成了一个Func,并且添加了lambda等可调用对象的封装支持。
Event内部含有一个Func数组,存放,本身重载了operator()(TArgs… args),当Event本身被调用时,Func数组内的可调用对象一个一个地被调用,同时变长参数表TArgs…一个一个被完美转发进Func的调用参数内,达成了callback的目的。
void operator()(TArgs... args) const
{
for (auto&& handler : handlers)
{
handler(PerfectForward<TArgs>(args)...);
}
}
下面说收Func的设计,std::function相比于Func,其最大的弱点就是——不能封装成员函数指针,众所周知,成员函数指针在调用的时候是需要一个对应的对象指针的存在的,而function并不能做到这个,为此,C++还提供了std::mem_fn函数,接受对象指针和成员函数指针,返回一个可调用对象,这本身是可以的,问题是在这个对象本身和std::function并无任何关联,类型名称也是奇观的下划线开头,平常只能用auto自动推断,如果我想把std::function和这个东西生硬的结合起来,还不如自己写一个。
Func本身包含一个可调用对象的智能指针,利用operator()的重载调用智能指针中的可调用对象,而这个可调用对象是该重点说的东西:
C++有三种不同的可调用对象——普通函数指针、成员函数指针、仿函数,这三种东西可以分别封装成三个可调用对象,然后重点来了——让他们共同继承自一个相同的基类,并且这个积累有一个纯虚的operator()成员,这个时候就能解释为什么Func内是一个只能指针而不是一个对象副本了,因为没办法愉快的利用多态调用不同的可调用对象。
有了Func,有了Event,这个事件回调机制就齐了。
p.s.前几天无意中看到了boost::signal,这是一个加强版的Event-EventHandler设计,可以给事件回调进行分组管理,临时禁用某些回调,或者批量解绑回调等,之后的时间,写完了自己用的Map和List,要尝试实现一下这个。
p.p.s.顺便感叹写boost的大牛们在没有变长模板存在的时代硬生生的用模板参数堆出了最高支持9个参数的boost::signal,真是太厉害了
feature3 合并Destroy和析构函数,使用智能指针代替手动析构资源
这里又要吐槽Win32API的三个消息WM_QUIT, WM_CLOSE, WM_DESTROY了,虽然从设计角度,这三个消息并没有冲突,但是对于使用者来说,相似的事件名称的确会产生混淆。也许是为了照顾上古时期C语言不支持过长标识符的设计,我想把他们分别命名成WM_APPLICATIONQUIT, WM_ASKWINDOWCLOSE, WM_WINDOWDESTROYED会好很多,这样也能一目了然地明白三个消息的意义——程序退出,请求关闭窗口,窗口摧毁完毕
原本这个程序的消息机制是这样的,窗口接受WM_CLOSE消息,关闭自身的同时如果发现自己是主窗口,那么呼叫Application退出(此时还未从主窗口消息处理函数中退出),Application管理着程序所有的窗口和控件,Application对窗口一个一个调用Destroy函数,然后再用delete析构调他们,Destroy函数会一层一层地销毁掉对象实际占有的资源,到基类WinControl的Destroy内调用DestroyWindow时,WM_DESTROY会生成然后立即发送给消息处理函数处理,这时候,窗口还没有从Application的列表里删除,Application的消息处理函数找到列表里的窗口对象,将WM_DESTROY消息传递给他处理,这时候窗口释放掉所有的附带对象包括Timer,反注册快捷键,最后调用PostQuitMessage,程序正常退出。
将Destroy写进析构函数里之后,由于调用DestroyWindow的时候,窗口已经从Application的列表中被删除,WM_DESTROY找不到处理者,被默认处理,没有PostQuitMessage被调用,所以窗口已经没了,消息循环还在跑,程序还没有完全退出,这时候只要在负责delete所有窗口的函数的最后加上PostQuitMessage,就能正确的结束消息循环,关闭程序。
就先说到这里吧。
Win32API界面库 - Project wheels 工程基础部分完成的更多相关文章
- 【液晶模块系列基础视频】4.5.X-GUI图形界面库-进度条等函数简介
[液晶模块系列基础视频]4.5.X-GUI图形界面库-进度条等函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ...
- 【液晶模块系列基础视频】4.4.X-GUI图形界面库-画tab函数简介
[液晶模块系列基础视频]4.4.X-GUI图形界面库-画tab函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ...
- 【液晶模块系列基础视频】4.3.X-GUI图形界面库-画box函数简介
[液晶模块系列基础视频]4.3.X-GUI图形界面库-画box函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ...
- 【液晶模块系列基础视频】4.2.X-GUI图形界面库-画矩形函数简介
[液晶模块系列基础视频]4.2.X-GUI图形界面库-画矩形函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址: ...
- 【液晶模块系列基础视频】4.1.X-GUI图形界面库-画线画圆等函数简介
[液晶模块系列基础视频]4.1.X-GUI图形界面库-画线画圆等函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地 ...
- C++ 100款开源界面库 (10)
(声明:Alberl以后说到开源库,一般都是指著名的.或者不著名但维护至少3年以上的.那些把代码一扔就没下文的,Alberl不称之为开源库,只称为开源代码.这里并不是贬低,像Alberl前面那个系列的 ...
- 仿迅雷播放器教程 -- C++ 100款开源界面库 (10)
(声明:Alberl以后说到开源库,一般都是指著名的.或者不著名但维护至少3年以上的.那些把代码一扔就没下文的,Alberl不称之为开源库,只称为开源代码.这里并不是贬低,像Alberl前面那个系 ...
- 开源的DirectUI界面库
1. duilib简介 duilib是一个开源的DirectUI界面库,简洁但是功能强大.而且还是BSD的license,所以即便是在商业上,大家也可以安心使用.现在大家可以从这个网站获取到他们所有的 ...
- VC UI界面库大集合
Guitoolkit http://www.beyondata.com/pwc.html The Ultimate Toolbox http://www.codeproject.com/KB/MFC/ ...
随机推荐
- android 中theme样式的解释
android:theme="@android:style/Theme.Dialog" : Activity显示为对话框模式 android:theme="@androi ...
- 用jQuery Mobile搭建一个简单的手机页面
1.新增html页面. 2.声明html5Document. 3.载入jQuery Mobile Css.jQuery与jQuery Mobile链接库. 4.使用jQuery Mobile定义的ht ...
- 【个人使用.Net类库】(4)验证码类
验证码是现在管理系统常用的一种保护用户帐户信息的一种功能. 验证码可以有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录尝试,虽然这可能是我们登录麻烦一点,但是对用户的密码安全来 ...
- WP8.1 Study17:网络之后台下载/上传及HttpClient
一.后台下载/上传 1.简介 使用BackgroundTransferGroup可以十分方便操作上传及下载文件,BackgroundDownloader和BackgroundUploader类中的方法 ...
- golang——channel笔记
1.for i := range channel { //... } 相当于 循环进行 i<-channel,直至close(channel) 2. · 给一个 nil channel 发送数据 ...
- ajaxsearch要点1
ajaxsearch中必须将form的class定义为pagerForm,才能在foot中submit按钮得到值
- Objective C类方法load和initialize的区别
Objective C类方法load和initialize的区别 过去两个星期里,为了完成一个工作,接触到了NSObject中非常特别的两个类方法(Class Method).它们的特别之处,在于 ...
- iOS学习之六种传值方式
iOS页面传值方式 应用于: 两个互动的界面:1)页面一跳转到页面二,页面一的textField的值传给页面二的label.2)A页面跳转到B页面,B页面再跳转回A页面(注册页面跟登录页面) 两个不互 ...
- 关于Let和var声明变量的区别
Let是ES6中添加进来的一个关键字,用于声明变量,其法与var声明变量相同,不同点在于其作用域(块级). 举例可以看出其具体差别 for(var i=0;i<5;i++){ console.l ...
- Warning: Attempt to dismiss from view controller <UIViewController: 0x17d71c10> while a presentation or dismiss is in progress!
昨天 调试程序 已经快要上线了 突然有个BUG 找了半天 才找到是因为这个警告 但是 解决这个警告又花了一天的时间 试了各种消除控制器的方法 都不可用 其中 并且 有这个bug 手机真机测试完全没问 ...