我工作的前十几年都是写 Windows 程序过来的,经历了 Windows 程序开发的所有历程,从早期Delphi, VB的快速开发模式到后来的MFC,到后来自绘,然后是开源脱离了 Windows。
控件
使用操作系统提供的模式化控件写代码没有什么成就感,这类应用需求变得越来越少,产品界面都趋向于花哨、自定义皮肤方向,主流的聊天程序,音乐播放器,连下载程序、杀毒软件都是如此。所以当时很多人都在研究Windows系统控件的自绘,就是改变系统控件绘制、响应。当时微软有幸泄漏了Windows 180MB的源代码,里面有几户所有用户态控件,甚至IE浏览器代码,我几乎拜读了一遍。利用过一些没有在MSDN文档里出现的值、结构来绘制 ListView, ComboBox, RichEdit等。效果是出来了,但是一旦系统大升级可能就失效了,好在产品生命周期都不比Windows XP更长。
这种方式有个致命的天花板,就是控件库的文档,由于Windows是闭源的,只有文档可以依赖。开发人员能做的很有限,绘制效率、操作、自定义程度都是难题。于是开始出现全自绘的代码,有DirectUI等几个吧。但是我转向了开源。
开源的 2D 矢量自绘制的界面
当时我看遍了当时所有的可选项,wxWidgets, QT等, http://boost.org 邮件组里有讨论UI库,里面几乎有所有的实现。我选择了一个矢量绘制实现(http://ultimatepp.org,简称U++/UPP),这是一个欧洲人做的比较小众,整个代码库大概有40万行代码(核心也有10万+行),所有控件都实现了,支持Windows, X-Windows。但是效果惊人,各种半透明、渐变、圆角、动画,还有文字效果和编辑、甚至图文混排都脱离了操作系统的控制,不需要和系统资源(GDI Handle)和控件交互,从此没有操作系统的天花板了,就是无所不能了。甚至实现了界面编程特点的”STL”。
C++在界面开发领域的地位
C++语言衍化了这么多年,一直在推出新标准,但是写界面的方法一直没有太大变化,不能不说整个界面编程是个被人遗忘的技术领域,有想法的人都去做更有挑战性的事情了吧。但是UPP往前进了,把MFC,Java UI的方法至少甩出20年。界面布局、消息响应、图片资源文件的访问等都做到了极致。甚至连编译速度比Visual Studio IDE快十倍(虽然底层还是用cl, link)。
说一下布局的支持吧。这是一段可执行的代码:
LAYOUT(DlgLayout, 208, 64)
ITEM(Label, dv___0, SetLabel(t_("Label")).LeftPosZ(8, 36).TopPosZ(8, 19))
ITEM(EditString, text, LeftPosZ(48, 92).TopPosZ(8, 19))
ITEM(Option, option, SetLabel(t_("Option")).LeftPosZ(8, 108).TopPosZ(32, 15))
END_LAYOUT
完成了三个控件的布局和容器缩放的规则,比起如今iOS/Android的界面布局方式好了不少吧。
消息响应
struct MyAppWindow : TopWindow {
Button button;
void Click() { PromptOK("You have clicked the button!"); }
typedef MyAppWindow CLASSNAME;
MyAppWindow() {
Title("My application with button");
Add(button.LeftPos(10, 100).TopPos(10, 30));
button.SetLabel("Click me!");
button <<= THISBACK(Click);
}
};
能在没有boost::function的年代就把函数指针利用得优雅无比。相比Objective-C里的block, selector其实更容易使用。
浏览器界面技术也是类似,最早期的浏览器里甚至直接使用操作系统控件实现HTML控件,导致因为页面耗费资源太多而无法加载过于复杂的页面。之后从 Firefox 用了 cairo 作为渲染引擎,Chrome开发了自己的 skia。
观点
手机应用界面开发和 Windows 程序界面开发的历程完全一样。开发者都会经历IDE快速开发,手工布局,自定义绘制,完全重头实现这些阶段。相互借鉴和参考还是有些意义的。
比较诡异的是Android采用的Java在写界面程序方面几十年没有变化,虽然是号称比C++高级的语言,这货能把代码写得如上面般简洁么?在Android上也不可能使用纯C++(不使用jni)编写普通界面应用。iOS的 Objective-C 也是如此,见过大部分程序员只用代码布局,nib基本不用的,出了StoryBoard可能稍微好了一点。这两家独大,让C++在移动应用界面开发领域几乎无用武之地。
但是Google的Flutter彻底颠覆了这个流程,直接跳到了矢量绘制的阶段,我还需要期待什么呢?
这个结论有点突兀,有点诡异。过了好多年了,对个中细节实在没有太多心气劲深入,很多值得深入的地方没有一一描述清楚。大家凑合看吧,什么地方有争议可以提出来。
参考链接