应该把整个程序运行过程分解为:
- 描述一个界面(前端)
- show出来
- 进入无限循环
- 在循环里按照刷新频率show这个界面
- 每次循环里还检测是否有输入,如果没有,就继续下一次循环
- 如果有,就像控制台程序一样,接受输入,给出输出
- 当遇到销毁窗口的输入时,退出循环(从而不再show,也不再处理输入,并且从main return回去,被操作系统回收了申请的内存以及画笔权限之类的资源)
也就是说,我把一个窗口程序分解为
- 定义图形
- 重复画图
- 对输入给出输出的类似控制台程序
- 在main函数,我在栈上(或者堆上)申请了几个类变量,这些变量是我的窗口的组件,设置他们的各种属性(比如外观),设置他们的从属关系,然后把他们用layout布局好,用show函数显示出来。显示出来的是一个图形,当然,类不止有外观方面的属性,所以这其实是一个前端
- 进入消息循环,这个图形一直显示着(不知道是不是按照刷新频率不断地执行show函数)
- 以上就完成了在屏幕上一直显示一个图形的任务,然后,接下来的任务就是这个程序接受输入,然后输出结果的过程。
- 接受的输入有: 键盘、鼠标等等的输入,又或者说这些输入设备他们的状态持续性(被读取的时间点是离散的)、间歇性地被系统函数读取,然后,如果我们的鼠标点击了我们写的这个窗口程序的某个按钮,就会把这个状态PUSH进我们的程序的消息队列,而因为我们的程序在消息循环中一直扫描该队列,所以主程序可以读到输入,并把输入分发给组件(也就是调用组件的函数,把输入作为参数传给函数)
- 如果前后端不分离,那么我们可以直接在组件里定义函数,这些函数对输入给出输出,然后直接输出来
- 但是,这样程序就不解耦了,这样我们要对输入到输出的映射进行修改就需要修改这个组件的类成员函数
- 如果我们换一种实现方式,组件接收到输入(也就是自己接受输入的函数被调用)后把自己的状态的变化发射出去(用SIGNAL函数)
- 所谓发射出去,我猜测如下
- GoF观察者模式的经典实现(就是每个组件的消息接收函数都调用一次)
- 组件也有消息循环(这或许需要多线程,毕竟主程序在进行消息循环,如果组件也无线循环那要跑哪个循环)
- 把该消息放在共享的那块内存,然后每个组件都执行一次消息循环