Sunday, May 03, 2009

Gtkmm v.s. Qt

Gtkmm 自己的手册上也对 Qt 进行了比较,另外在 FAQ 里面也有所阐述,我们在这里记录一下:

Qt 产生的时代比较早,那个时候 C++ 标准尚未成熟,而 Gtkmm 产生较晚,那个时候 C++ 标准和 STL 都比较成熟。使用 gtkmm,使用的方式更偏向于 C++ 的风格,可以使用继承、多态,并且由于 gtkmm 使用的机制(libsigc++,在对象里 composite signal 对象)能更好的利用 C++ 编译实现 type-safe,而不是依赖于运行时检查类型匹配。

在内存管理上,gtkmm 之于 Qt 稍微灵活一些,一般说来 Qt 里面通过 QWidget 一线继承下来的有一个所谓的 parent,这使得我们 new 出来的对象可以不必手工 delete,因为通过 parent 的释放,这个 QWidget 也将被自动的释放。但是这样做了,我们就不能通过自己的代码改变该 QWidget 的生存。gtkmm 提供了额外的方式,Gtk::manage()。

从继承的方式我们也知道,Qt 通过额外的 QMetaObject,这使我们在继承的时候不能遗忘 Q_OBJECT 宏以维持正常的 signal/slot 机制,同时在该分支中希望做多继承其实不必要。换言之 Qt 的设计更偏向于 Java 一些。gtkmm 虽然没用这些比较 tricky 的地方,但是也会因此丧失一些 Qt 的优点。比如 Qt 不仅仅包含一整套 GUI 设计的类库、工具,所有的外围部件,如 XML、网络等都使用的统一的设计,相同的通讯机制。而 gtkmm 充其量只算把 GUI 设计部分解决了,如果需要其他的功能,需要使用别的库,这在一定程度上对程序员提出了更高的要求,因为很可能必须自己写一个 wrapper(如果是一个 C 库,不具备 signal/slot 的能力),又或者是具有 signal/slots 能力的库,如何将两部分整合在一起呢?

有一点 Qt 通过 QMetaObject 实现的,如 signal/slot 的 auto connection,我们只需要为某个 GUI 设计好界面,然后通过多继承也好,UiTools 直接读取 ui 文件也好,不需要额外的代码,signal/slots 就连接好了,不过这也限制了这类 signal/slots 对象必须是 QObject。gtkmm 应该是不能这样实现自动连接,但是 ligsigc++ 允许将 signal 连接到普通的函数或者成员函数,这也使得我们能够比较方便的实现 signal/slot 的连接过程。

gtkmm 可能更加接近 STL,有人认为这是好事,因为标准就是好;也有人不这么认为,因为相反提供的功能比较有限,不如 Qt 很多类更适合编程人员的上手。

gtkmm 的外围工具不如 Qt 那么专门,比如 qmake、uic 和 moc;我们更常用的 pkg-config 和 autotools 将和 gtkmm 更好的协同工作。当然 Qt 的 qmake 使用 pkg-config 的也相当容易了。

Qt 似乎多线程方面做得更好一些,很多关键性的部分都有 mutex 等出现保证原子操作性,而 gtkmm 在这部分似乎做的还差的很远,因为 FAQ 里面说道倾向用单线程 -,-b

关于 qmake 的一个诡异的事情

不知道为什么,巨汗,本来以为那个 scope 可以很容易实现在 debug 和 release 版本下把目标文件放在不同的目录下,只需要

debug {
 DESTDIR = debug
}
release {
  DESTDIT = release
}
就完了,结果非常的 frustrating,网上看见不少人跟我有类似的抱怨,就是写了但不 work,比如有的是希望 LIBS 不一样什么的,但是居然有人说没这回事,可是在我机器上这个事情发生了 N 次了。你看看生成的 Makefile.Debug 和 Make.Release 好了,这样写最后 target 都是 release/$$TARGET,天知道为啥这个 scope 就被忽视了。

最后现在用下面的方法“解决”了,其实不是解决吧,因为我也不知道为啥。

CONFIG(debug,debug|release) {
  DESTDIR = debug
} else {
  DESTDIR = release
}
最囧的是,必须把这句话放在 CONFIG 变量前面... 我到...