离上次发博文过去了好久,先是要忙一个机器人的项目,然后就是部门的事情和考试周复习,然后就到了考试周,趁着复习的间隙,拾起了寒假时候抄的界面库,修掉了从前的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 工程基础部分完成的更多相关文章

  1. 【液晶模块系列基础视频】4.5.X-GUI图形界面库-进度条等函数简介

    [液晶模块系列基础视频]4.5.X-GUI图形界面库-进度条等函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ...

  2. 【液晶模块系列基础视频】4.4.X-GUI图形界面库-画tab函数简介

    [液晶模块系列基础视频]4.4.X-GUI图形界面库-画tab函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ...

  3. 【液晶模块系列基础视频】4.3.X-GUI图形界面库-画box函数简介

    [液晶模块系列基础视频]4.3.X-GUI图形界面库-画box函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ...

  4. 【液晶模块系列基础视频】4.2.X-GUI图形界面库-画矩形函数简介

    [液晶模块系列基础视频]4.2.X-GUI图形界面库-画矩形函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址: ...

  5. 【液晶模块系列基础视频】4.1.X-GUI图形界面库-画线画圆等函数简介

    [液晶模块系列基础视频]4.1.X-GUI图形界面库-画线画圆等函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地 ...

  6. C++ 100款开源界面库 (10)

    (声明:Alberl以后说到开源库,一般都是指著名的.或者不著名但维护至少3年以上的.那些把代码一扔就没下文的,Alberl不称之为开源库,只称为开源代码.这里并不是贬低,像Alberl前面那个系列的 ...

  7. 仿迅雷播放器教程 -- C++ 100款开源界面库 (10)

      (声明:Alberl以后说到开源库,一般都是指著名的.或者不著名但维护至少3年以上的.那些把代码一扔就没下文的,Alberl不称之为开源库,只称为开源代码.这里并不是贬低,像Alberl前面那个系 ...

  8. 开源的DirectUI界面库

    1. duilib简介 duilib是一个开源的DirectUI界面库,简洁但是功能强大.而且还是BSD的license,所以即便是在商业上,大家也可以安心使用.现在大家可以从这个网站获取到他们所有的 ...

  9. JUCE 界面库显示中文乱码问题

    JUCE 界面库显示中文乱码问题 环境: Windows7 64位 旗舰版 Visual Studio Ultimate 2012 JUCE 4.1 问题描述: 直接使用juce::String存储中 ...

随机推荐

  1. 分享两个BPM配置小技巧

    1.小技巧 流程图修改后发布的话版本号会+1,修改次数多了之后可能会导致版本号很高,这个时候可以将流程导出,然后删除对应的流程包再导入,发布数据模型和流程图之后,版本清零 2.小技巧 有的同事入职后使 ...

  2. js base64加密,后台解密

    这是为了解决页面发送post请求,传输密码,在页面的控制台可以看到密码的明文,所以先用base64把要传输的密码转换为非明文,然后在后台解密处理. base64encode.js // base64加 ...

  3. 安天AVLTeam送福利喽~~

    #福利来了#  duang~duang~duang~ 安小天帮你辨别短信真伪!!! 是不是经常收到真假难辨的[疑似诈骗短信]是真的?是假的? 傻傻分不清楚 现在不用怕啦!!! 遇到这种情况,只需手机截 ...

  4. Linux rpm 命令参数使用详解[介绍和应用]

    RPM是RedHat Package Manager(RedHat软件包管理工具)类似Windows里面的“添加/删除程序” rpm 执行安装包 二进制包(Binary)以及源代码包(Source)两 ...

  5. ibatis传入数组或List

    小结一下ibatis框架下,传入参数为数组类型或者是List类型的sql写法.标签里面都不需要表名 1.传入字符串数组,不需要标明parameterClasss,数组和List类型对象一样都可以用&l ...

  6. 算法_栈的Java的通用数组实现

    栈是一个常用的最简单的数据结构,这里提供了其实现.内部维护了一个数组,并且可以动态的调整数组的大小.而且,提供了迭代器支持后进先出的迭代功能.Stack的实现是所有集合类抽象数据类型实现的模板,它将所 ...

  7. Power Point已经检测到你的显卡可能无法正确配置

    Microsoft PowerPoint打开ppt时提示信息 PowerPoint已检测到你的显卡可能无法正确配置最佳的幻灯片播放体验(“Power Point has detected that y ...

  8. mysql备份恢复数据库据/表

    备份单个数据库,只备份表,如要恢复,必须先创建一个数据库[root@s]# mysqldump -u root -p dbname1 > dbname1.sql[root@s]# mysql - ...

  9. JComboBox

    package swing.combox; import java.awt.FlowLayout; import javax.swing.DefaultComboBoxModel; import ja ...

  10. java学习面试精华

    1.线程状态转移 (1)线程生命周期中的5种状态 新建(New).就绪(Runnable).运行(Running).阻塞(Bolocked)和死亡(Dead) 新建(New):程序使用new关键字创建 ...