前面我们讨论了很多关于编写跨平台程序的若干问题。不过有时候,我们也不得不编写一些与平台相关的代码。为了编写这种更加 native 的程序,我们就来开始详细阐述下编写平台相关的代码所需注意的事项。
编写平台相关的代码,可能会用到 #ifdef 这个预处理指令。我们可以使用 Qt 内置的几个宏,结合 #ifdef 来判断当前是在哪个平台下编译。这也是 C++ 条件编译很重要的一种应用。
Qt 给我们提供了以下几个宏,用于判断当前平台:
Q_WS_MAC
:Mac OS XQ_WS_X11
:X11Q_WS_QWS
:Qt for Embeded LinuxQ_WS_S60
:S60Q_WS_WIN
:Windows
我们可以使用下面的代码来判断一下:
#ifdef Q_WS_WIN // code for Windows #elseif Q_WS_MAC // code for Mac OS X
在使用预处理指令进行条件编译之后,我们还可以使用QWidget::winId()
函数来获取平台相关的窗口句柄。注意,这个函数是平台相关的,因此,带有这个函数的代码一般都需要事先判断平台,否则很可能会有错误。QWidget::winId()
在不同平台的返回值也不一样:
- Windows 平台下:HWND
- Cocoa 平台下:NSView*
- X11 平台下:handle
利用QWidget::winId()
的返回值,我们可以调用本地 API。例如使用 HWND 窗口句柄可以调用 Windows Vista 或者 Windows 7 特有的函数。
下面我们给出一些平台相关的程序要点。
Mac OS X
Mac OS X 的应用程序看上去很华丽。在开发 Mac OS X 的程序时,首要要注意使用高分辨率的应用程序图标;其次,像前面曾经提到的,如果要使用系统通知区,需要使用灰度图做图标。
注意一下,Mac OS X 的应用程序菜单栏与 Windows、GNOME 2 或者 KDE 有所不同。Mac OS X 的程序菜单栏是与系统状态栏合二为一的,因此,程序应该提供一个默认的菜单栏。为实现这一目的,我们需要在创建 QMenuBar
时,注意不要设置 parent 参数。这样,这个QMenuBar
创建出来就是默认菜单栏。
使用QMainWindow::setUnifiedTitleAndToolBarOnMac()
函数可以让我们的程序看起来更合理一些:

在调用QMainWindow::setUnifiedTitleAndToolBarOnMac()
之前,我们可以看到,标题栏和工具栏有一个明显的分隔界线。当我们调用QMainWindow::setUnifiedTitleAndToolBarOnMac()
之后,我们的程序就会变得更加自然一些:

既然设置这个函数让我们的程序看起来更加合理,为什么 Qt 不默认设置呢?这是因为,当我们设置这个属性时,工具栏变得不可拖动,并且工具栏的 break 也不可见(仔细对比一下上面两个截图)。在全屏情况下,工具栏会被隐藏掉;当程序大小不合适时,自定义组件会被隐藏掉。基于这些原因,Qt 就不会将其设置为默认选项了。请注意下面两个对比图中,当程序尺寸较小时,QToolBar
上面组件的显示问题:


Mac OS X 的 dock 可以添加菜单。我们可以使用qt_mac_set_dock_menu()
函数来实现这一点。

需要注意的是,这个函数虽然是一个 C++ 函数,但是并没有包含进头文件中,需要你自己去 extern 声明一下:
QMenu *menu = new QMenu; // Add actions to the menu // Connect them to slots ... extern void qt_mac_set_dock_menu(QMenu *); qt_mac_set_dock_menu(menu);
Qt 会对一些菜单项进行自动排列。比如,如果你的菜单是“关于”、“设置”、“首选项”、“退出”等等,我们可以给它们分配一个角色,Qt 则会根据这些角色对菜单项的顺序作出正确的排列。方法是,设置QAction::menuRole
属性,例如:AboutRole、PreferencesRole、QuitRole 或者 NoRole。举例来说,我们可以将“设置”菜单项作为 Mac OS X 的Application::preferences
。

关于有关 Mac OS X 平台上的介绍就到这里。因为豆子目前也没有 Mac 系统,很多东西也无法亲自测试。这里推荐一篇类似的文章,希望在以后开发时能够加以参考:http://doc.qt.nokia.com/qq/qq18-macfeatures.html。