编写 native 风格的 Qt 程序(2)

我们先从 Style 说起。所谓 Style,也就是风格,可以理解成把程序运行起来,第一眼看上去的的样子,也就是程序的第一印象。这种第一印象往往左右着用户的想法。例如,Safari 原本是 Apple 在 MacOS 下的默认浏览器。后来,Apple 把它移植到 Windows 平台,但仍旧保留了 Apple 的外观。这样一来,尽管 Safari 看起来很华丽,却与 Windows 的风格格格不入(下图出自 http://www.dtgeeks.com/journals/article/safari_for_windows/):

我们不能简单说这是 Apple 的设计失败之处。但是,如果你自己的程序留给用户的第一印象是这种样子的话,不知道用户能不能很好的接受呢?比如,你见过有几个 Windows 程序会把 title 放到标题栏的居中位置?这分明就是 Apple 自家的风格。在本文中,我们正是要避免出现这种格格不入的情况。

这就是 Style,用户的第一印象。下面我们来看看 Qt 的表现:

上面是在 Windows XP 下使用 designer 拖画出来的界面,然后原封不动拿到 Ubuntu 下编译出来的结果。我们很容易可以看出哪一个是 XP 下的窗口,哪一个是 Ubuntu 下的窗口。在 Ubuntu 下,除了组件大小有问题之外,其他部分同系统都能够很好地融合在一起。下面我们注意一下细节:Windows 下,OK 按钮在在 Cancel 的前面,而 Ubuntu 下,OK 则在 Cancel 后面。这一点是使用QDialogButtonBox的效果。Qt 能够为我们处理好这种细节,不需要我们自己过多考虑这种细节问题。

Qt 实际是使用QStyle这个类来实现不同平台的特有样式的。QStyle主要完成的工作是,绘制出一个合适的系统外观;确定组件的大小和形状(例如上面的水平滑块的样式)。在这里,我们的建议是,不要强制指定某一种风格。如果你需要手动编译 Qt,记得加上所需要的头文件,例如在 X11 平台下链接到 GTK+ 的库,而在 Windows 平台下 链接到 Windows SDK。另外,在编写自定义组件时,注意使用系统提供的绘制组件,而不是自己用图片替代。先看下面两张截图(来自 Nokia 2009 开发者大会 PPT):

这两个相当类似的界面来自同一个程序:QtCreator。你能够分辨出它们分别来自什么平台吗?如果熟悉的话,我们可以很明显地从滚动条认出,第一个来自 Windows,确切地说是 Windows Vista 或者 Windows 7;而第二个来自 MacOS X。这是 Qt 为我们实现的,不是我们的重点。重点是细节:不同平台下,代码折叠的样式是不同的。这里只是为了强调一点:不要试图用图片来显示这种通用的组件。这里的代码折叠其实使用 tree 实现的,而 Windows,MacOS X 下 tree 的图标显然是不同的。我们应该遵循系统约定,Windows 下的折叠起来的图标是白色的,而 MacOS 下则是同展开时一样的灰色。那么,如何实现这一点呢?下面是关键部分的代码(代码细节我们会在后面的章节中详细阐述):

QStyleOption opt;
opt.rect = arrowRect;
opt.state = QStyle::State_Item | QStyle::State_Children;
if(expanded) {
    opt.state |= QStyle::State_Open;
}
style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painer, this);

Leave a Reply