進化するQt-Qt最新事情2009

第3回 Qt 4.5最新動向

この記事を読むのに必要な時間:およそ 5 分

バグ修正や追加機能の調べ方

以前のQtは,リリース情報は概要程度で,変更履歴を読んでも,どのようなバグが修正されたのかは,ほとんどわかりませんでした。最近は,以前に比べれば詳しく書かれるようになり,Task TrackerGitリポジトリのログを併用すれば手がかりが掴め,Gitリポジトリから修正パッチも作ることもできるようになっています。しかし,バグ修正や追加機能を調べるには,以下のような地道な手間が必要です。

  • リファレンスのWhat's New in 4.5を読む

  • 変更履歴changes-4.5.0を読む

  • Qt Assistantの全文検索機能でintroducedをキーにして検索し,さらにテキスト検索機能でintroduced in 4.5と付記されている記述を調べる。

    • (1)Qt Assistantのサイドバーの検索でintroducedをキーにして検索
    • (2)検索された項目をひとつずつ開きながら
    • (3)編集の検索機能で Qt 4.5 を検索して,記述内容を調べる
  • ソースコードを見て初めてわかる機能

    リファレンスにも変更履歴にも書かれていなくても,ソースコードを見ていて気が付き,開発元に確認するとサポートされている機能だと返事があったりします。

オブジェクトシステムの変更

QMetaObject

QMetaobjectのextradata の構造が変わり,static_metacall が追加されています。これにより,新しいメソッド newInstance() が呼び出されるとインスタンスが生成できます。つまり,コンストラクタのイントロスペクションができ,コンストラクタの呼び出しが可能 ⁠Invokable)⁠ になっています。これに関連して,以下のメソッドが追加されています。

QMetaMethod QMetaObject::constructor()
int QMetaObject::constructorCount()
int QMetaObject::indexOfConstructor()
QObject* QMetaObject::newInstance()

コンストラクタを呼び出し可能にするには,Q_INVOKABLE がコンストラクタの宣言に指定してある必要があります。Qt 4.5 でこの指定がされているコンストラクタは,以下のもののみです。

Q_INVOKABLE explicit QObject(QObject *parent=0);

サンプルコードmetaconstructor.cppをコンパイルして,実行すると以下のような実行結果となります。

$ ./metaconstructor 
Foo() 0: Foo(0x50a320) 
Foo() 0: Foo(0x5109b0) 
Foo() 0: Foo(0x5109c0) 
Foo() 0: Foo(0x5107f0) 
Bar() 0: Bar(0x511fc0) 
Foo() 1: 10 Foo(0x510800) 
Foo() 1: 10 Foo(0x510810) 
Foo() 2: 100 10 Foo(0x512120) 
Foo() 2: 100 10 Foo(0x512180) 
$ 

サンプルコードを説明します。

リスト1 metaconstructor.cpp:

 1: #include <QtCore>
 2: 
 3: class Foo : public QObject
 4: {
 5:     Q_OBJECT
 6: 
 7: public:
 8:     Q_INVOKABLE explicit Foo(QObject* parent = 0) : QObject(parent) { 
 9:         qDebug() « "Foo() 0:" « this; 
10:     }
11:     Q_INVOKABLE explicit Foo(int arg1, QObject* parent = 0) : QObject(parent) { 
12:         qDebug() « "Foo() 1:" « arg1 « this; 
13:     }
14:     Q_INVOKABLE Foo(int arg1, int arg2, QObject* parent = 0) : QObject(parent) {
15:         qDebug() « "Foo() 2:" « arg1 « arg2 « this; 
16:     }
17: };
18: 
19: class Bar : public QObject
20: {
21:     Q_OBJECT
22: 
23: public:
24:     Q_INVOKABLE explicit Bar(QObject* parent = 0) : QObject(parent) { 
25:         qDebug() « "Bar() 0:" « this; 
26:     }
27:     Q_INVOKABLE explicit Bar(int arg1, QObject* parent = 0) : QObject(parent) { 
28:         qDebug() « "Bar() 1:" « arg1 « this; 
29:     }
30:     Q_INVOKABLE Bar(int arg1, int arg2, QObject* parent = 0) : QObject(parent) {
31:         qDebug() « "Bar() 2:" « arg1 « arg2 « this; 
32:     }
33: };

クラス Foo と Bar のコンストラクタに Q_INVOKABLE を付けて,コンストラクタを呼び出し可能にしています。

34: 
35: QObject* createObject(const QMetaObject* metaObject)
36: {
37:     return metaObject->newInstance();
38: }

どのクラスかは,判断せずにメタオブジェクトの newInstance() を呼び出しているだけですが,メタオブジェクトのクラスが異なれば,それに応じたインスタンスが作成されます。

39: 
40: int main(int argc, char** argv)
41: {
42:     QCoreApplication app(argc, argv);
43: 
44:     QObject* object = Foo::staticMetaObject.newInstance();

スタティックメタオブジェクトを直接アクセスして,newInstance()を呼び出してもFooインスタンスを生成できます。

45:     
46:     QGenericArgument parentArg = Q_ARG(QObject*, 0);
47:     object = Foo::staticMetaObject.newInstance(parentArg);                      // Returns Foo

親オブジェクトを指定するだけのコンストラクタ呼び出しです。

48: 
49:     const QMetaObject* metaObject = &Foo::staticMetaObject;
50:     object = metaObject->newInstance(parentArg);
51:     object = createObject(&Foo::staticMetaObject);                              // Returns Foo!
52:     object = createObject(&Bar::staticMetaObject);                              // Returns Bar!

createObject() に,このようにメタオブジェクトを渡してもクラスに対応したインスタンスが生成されます。

53:    
54:     QGenericArgument intArg1 = Q_ARG(int, 10);
55:     object = Foo::staticMetaObject.newInstance(intArg1, parentArg);             // Returns Foo
56:     object = metaObject->newInstance(intArg1, parentArg);                       // Returns Foo
57:     
58:     QGenericArgument intArg2 = Q_ARG(int, 100);
59:     object = Foo::staticMetaObject.newInstance(intArg2, intArg1, parentArg);    // Returns Foo
60:     object = metaObject->newInstance(intArg2, intArg1, parentArg);              // Returns Foo

引数を指定したコンストラクタ呼び出しです。

61: 
62:     return 0;
63: }
64: 
65: #include "metaconstructor.moc"

Q_SIGNAL と Q_SLOT

シグナルとスロットの宣言signalsとslotsに加えて,Q_SIGNALとQ_SLOTをメソッドの先頭に付ければ,シグナルとスロットを宣言できるようになりました。

Qt 4.6での宣言的ユーザインターフェース(Declarative UI)機能追加で,さらにオブジェクトシステムが変更されるでしょう。

おわりに

次回以降では,Qt 4.5で大きく変更されたQt Desinger,Qt Linguistについて説明します。

著者プロフィール

杉田研治(すぎたけんじ)

1955年生まれ。東京都出身。株式会社SRAに勤務。プログラマ。

仕事のほとんどをMac OS XとKubuntu KDE 4でQtと供に過ごす。