少年听雨歌楼上,红烛昏罗帐.壮年听雨客舟中,江阔云低断雁叫西风. 而今听雨僧庐下,鬓已星星也! 悲欢离合总无情,一任阶前点滴到天明。

2007年4月27日星期五

GUI库

昨天看了Crend的开发关于BT++的开发心得。他提及没有找到成熟好用的GUI库,因此暂时不打算开发BT++的界面。

关于界面,因为最近开发的需要,所以还是有不少的体会,这里分享一下。

我觉得从本质上来说,界面是软件不可或缺的一部分。很多人对此不以为然。可现代计算机的发展已经告诉我们,显示器和显示卡已经成为了大多数不可或缺的部分。用户都希望能够操作系统和应用程序能够提供易用漂亮的界面。有一些人用命令行和图形界面来区分高级用户和低级用户,这在我看来简直有一点逻辑混乱。

事实上却是,使用命令行有时候并不是宗教信仰问题,也不是高级低级的问题,而是被逼无奈。如果任何一个系统之下都有类似Visual Studio这样的开发工具,我不相信还有很多人去写生硬难懂的make文件 。

被逼迫的原因之一可能就是像Crend一样没有找到一个成熟好用的GUI库来构建应用程序,不得以只能使用命令行形式。那么我就来说说GUI库,拿Windows下的图形库举例。

Windows 有原生的API支持图形界面,包括窗体的创建、按钮的创建等等。这一点毫无疑问。问题就是拿这套东西去构建一个比较完整的图形界面,相信复杂度与你正要开发的应用程序相当,甚至还要更高。也就是说,如果Crend使用原生Windows API去构建图形界面,他还需要在他已有的程序基础上,多写5000-10000行代码。而我相信现在的BT++也未必能有这么多代码。

微软的MFC库倒是一个不错的选择。有各种类型图形元素的封装,从按钮到对话框。其实,大多数Windows下的应用程序都是选择MFC作为界面框架的。可是仔细考察以后就会发现,要使用MFC来构建一个类似uTorrent的界面(Crend鼎立推崇的一款BT软件)还是需要颇费一番功夫的。

首先,整个界面外观就需要布局。其次,界面中的布局可以根据鼠标拖动更改大小,并且做到大小自适应。这一点不太容易。然后就是下面的多标签(Tab)显示。每一个标签里面都是完全不同的控件布局。其中还有一个标签里面是下载和上传速度的动态显示。这在MFC里是不能够直接支持的,需要代码绘制。

当然,类似菜单Preference里面的左右分栏的效果也不是直接支持的。

我想说的是,uTorrent的界面元素看上去并不是太复杂,甚至是很基本的。然而,要想使用MFC构建这样的界面,需要的是对MFC比较熟悉,并且还可能需要写500-1000行代码左右。

如果是类似Office那样的界面呢?还增加一些透明效果,光影效果?

我最近使用.NET Framework来开发C#应用程序,用Windows.Forms来构建界面。应该说,比MFC要方便了不少,起码类似uTorrent这样的界面并不需要太多的编码就可以完成。可问题就是,当我还想更深走一步的时候,就遇到重重困难。比方说,我想自己做一个Textbox控件,来支持更多的功能,然而,要想在现有的一些界面控件上重新安排绘制过程,或者增加绘制代码,就显得很困难。然后还需要自己处理消息循环,而这些又都是在.NET Framework中去处理原生API,就更显得隔了一层。

好了,我的例子就说到这里。我的意思已经很明确了,就是说,一个所谓成熟的GUI库要具备哪些要素呢?

首先,提供基础的界面元素控件,比方说按钮,菜单,工具条。不能让开发者使用代码去构建这些基础的东西。

其次,要提供方便的布局方案。在开发系统的设计器中布局固然重要,但是很多情况下,软件在运行一开始,并不知道布局情况,或是在运行中,希望能够方便改变布局。因此,界面的布局方案是很重要的。MFC没有布局方案。Windows.Forms有专门的布局控件,但是这还不够。

第三点,处理消息或者叫事件要简单。要能够很容易去处理一些消息或者事件。MFC可能都需要使用一大堆生硬的宏。而Windows.Forms不需要这些,但也没有给开发者提供更多的处理事件的机会。除了标准的控件事件,Windows.Forms里面的不少控件都不能处理其他非标准的控件事件,需要挂接原生API。

第四,能够容易扩展。界面元素的绘制过程和方案能够进行重构。比方说,我可以通过继承或者其他的方式,改变标准按钮的绘制过程,从而得到新的按钮控件。而且,这种扩展应该是容易的。我仅仅希望改变按钮的外轮廓,我就处理外轮廓就行了,我不想管按钮内部的情况。你不能让我扩展轮廓还要从头画,这不行。

第五,界面和代码逻辑的集成性。这一点不太好理解。传统上,界面元素是没有语义的,按钮就是按钮,菜单就是菜单。和代码逻辑的集成,都是通过我们程序员来实现的。什么叫代码逻辑的集成?举例说,一个按钮代表了提取银行帐户里的前。那么,余额充足的时候,这个按钮应该是可用的;不足的时候就不可用。问题在于,这样的功能,只能通过我们用程序去判断余额,然后更改按钮的状态。一个小小的按钮没有问题,可是有时候,在一个系统中,某一个操作可能带来很多界面元素状态的改变,而且这种改变不是每一个元素都一样。通过程序,我们可能很难去收集现在这些元素的状态。更不要说如果是一个有插件的系统,我们也许都不知道有哪些元素需要去改变。所以,界面框架应该解决这样的问题,我只需要指明某个控件的什么状态与我的哪个逻辑是关联的,界面框架就自动去处理状态问题。

第六点,跨平台性。界面框架应该可以跨平台。这里指的平台不单单是操作系统,还有编程模型,比如Java、.NET、原生C/C++。不过这一点不太容易。

这是我归纳的六点关于GUI库的要求。现阶段普通的GUI库大多数都停留在第一个层次(如wxWidget,QT,GTK),仅仅是提供控件。当然,也有一些库提供了其他的功能。比方说Mozilla的XUL,提供了界面布局(XML),扩展性(使用类似HTML的方式,把界面元素和样式分离开,这样就可以通过样式来扩展元素的外观)。不过遗憾的是Mozilla只能使用C++开发,而且其依赖于Mozilla并不通用的框架模型XPCOM(类似微软的COM)。这多少有一点讨厌。

微软的Windows Presentation Foundation不错。基本控件、布局、扩展性都解决了不少,事件不知道如何。还增加了多媒体功能。不过跨平台性几乎没有。

Java的JFace也是使用XML进行布局。只是界面效果差强人意。Java在桌面应用程序上要走更远的话,界面的问题必须解决。

说了那么多,对Crend没有太多帮助:) 他还是只能暂时开发控制台程序,至少现在是这样的。

1 条评论:

Sleipnir 说...

第六点我觉得比较重要。要实现的话,我觉得还是像XUL那样,通过一个中间语言,把图形框架和后台分开。

另外,最近又搞了一些MFC,COM,ATL这些东西,太令人头疼了。虽然吹的COM怎么怎么好,但实际要写一个程序出来,太复杂了。可能还是经验不足吧。

对宏没有语言了……