Showing posts with label gtkmm. Show all posts
Showing posts with label gtkmm. Show all posts

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

Friday, April 17, 2009

Gtkmm 实现信号使用 libsigc++

这个 libsigc++ 只有一个终极目标,通过 C++ 的 template 机制实现 object 之间 signal/slot 功能。与 Qt 依赖 QMetaObject 不同在于,前者 hack C++ 的 template,而后者其实通过什么字符串等实现的,我们在这里仅仅实现一个简单的通信例子,介绍使用方法。我们将在后面的文章比较这两种实现需要的开销,细节。 整体上来看 libsigc++ 实现通信机制要简单很多,下面是 counter.hpp:
#ifndef COUNTER_HPP
#define COUNTER_HPP
#include <iostream>
#include <sigc++/sigc++.h>

class Counter {
int value ;
public:
sigc::signal<void, int> valueChanged ;
void setValue( int ) ;
Counter( int = 0 ) ;

friend std::ostream& operator<< ( std::ostream&, const Counter& ) ;
} ;

#endif
这里和 Qt 不同之处是需要通过 composite 一个 sigc::signal 的对象从而使得该类获得 signal/slot 处理能力,Qt 是依靠继承 QObject 获得(使用 Q_OBJECT 只是为了获得新的 QMetaObject)。下面是实现代码 counter.cpp:
#include <iostream>
#include "counter.hpp"

void
Counter::setValue( int val )
{
value = val ;
// emit the signal
valueChanged.emit( value ) ;
}

Counter::Counter( int val ) : value( val ) {}

std::ostream&
operator<< ( std::ostream& os, const Counter& c )
{
return os << c.value ;
}
这里通过 sigc::signal::emit 方法或者 sigc::signal::operator() 发送信号。最后是主文件 test_sigc.cpp:
#include <iostream>
#include <iomanip>
#include "counter.hpp"

using namespace std ;

int
main( int argc, char *argv[] )
{
Counter a, b( 10 ) ;

cout << "We have two counters, " << a
     << " and " << b << endl ;

a.valueChanged.connect( sigc::mem_fun( b, &Counter::setValue ) ) ;

a.setValue( 12 ) ;
cout << "We have two counters, " << a
     << " and " << b << endl ;

b.setValue( 5 ) ;
cout << "We have two counters, " << a
     << " and " << b << endl ;

return 0 ;
}
这里调用了 sigc::signal::connect 方法连接到一个 slot上,该 slot 是使用 sigc::mem_fun 产生的一个调用指定对象成员函数的 functor。其实 libsigc++ 提供了远远不止这些功能,我们将在下面仔细介绍其他的功能。 编译 libsigc++ 程序可以用 pkg-config,如
$ g++ -o test_sigc test_sigc.o counter.o `pkg-config sigc++-2.0 --libs`
通过以上例子我们可以大致获得一个使用该库的印象,需要 signal 功能的类通过 composition 或者继承(感觉似乎不大好,也许应该 protected 继承?)加入 sigc::signal<> 对象,该模板第一个参数是 signal 返回值,后面写上的话是 signal 的参数,可见通过 template 的检查保证了 type safe。之后使用 sigc::signal::connect 连接到一个 slot 上,该 slot 可以用 sigc::mem_fun() 创建(使用对象的成员函数)或者 sigc::fun_ptr() 创建(使用一般函数地址)。在该库编写的时候合适的地方通过调用 sigc::signal::emit() (或者重载的 operator())发出 signal。 简而言之,C++ 的 virtual function 为对象在继承过程中实现多态提供了基础,是一个同类函数同名操作的函数钩子;signal/slot 机制是为了对象之间互相通信留下的函数钩子。只是前者通过 vtable 很容易实现,后者需要依赖 template 和 functor 等比较高级的方式实现。

Friday, February 09, 2007

The relationship of several libraries

As is mentioned in the web sites of GTK+ and Gtkmm, there are several packages which are highly related to the topics here. Their relationship is of utmost importance to the understanding of the mechanisms of GTK+ and Gtkmm.

GTK+ is originally GTK, GIMP ToolKit. There are three supportive libraries, GLib, Pango and ATK. GLib provides lots of related functions that GTK+ widgets rely on, such signal system(here the term signal is different from the one Linux OS uses to send to processes). Pango handles layout and rendering texts. And ATK contains interfaces for accessibility.

However, the term GDK, GIMP Drawing Kit, can be found from time to time in the related materials. GDK is simply a wrapper for Xlib and if familiar with Xlib, it is not that essential here.

Gtkmm, a C++ wrapper of GTK+, provides a different developing model. It relies on libsigc++, glibmm. Here libsigc++ is a C++ flavor of realization of signal system.

GNOME project prospers on the GTK+. And based on Gtkmm, there is also a gnomemm library. Glade is a tool for creating GUI of GTK+ and libglade provides an alternative with XML as the GUI descriptor and dynamic creation of GUI. Not surprisingly, there will be a libglademm.

In order to compile several programs listed later, we need several packages:

  • GTK: gtk2, gtk2-devel
  • gtkglext: gtkglext, gtkglext-devel
  • gtkmm: gtkmm24, gtkmm24-devel
  • libglade: libglade, libglade-devel