2012/01/09

[qt]シグナルとスロット

シグナル、というと、Linuxのsignalを考えてしまうかもしれない。
しかしQtのシグナルは別のものである。
そして、Qtのシグナルは重要というか何というか、基本をなすしくみなのでちゃんと理解しておきたい。

参考URL:
http://labs.qt.nokia.co.jp/2010/06/17/signals-and-slots.html

GUIのウィジェットに関して言えば、シグナルは「イベント」みたいなものだ。
ボタンをクリックした、とか、テキストが変更された、とか。

自分でボタンを作ると考えた場合、クリックはこんな感じで対処しそうだ。

  1. ボタンはclassにする
  2. 汎用的にしたいので、クリックしたときに呼び出される処理をコンストラクタなどでコールバック登録する
  3. 専用のボタンなら、派生クラスを作ってクリックイベントは自分で実装

しかし、コールバック登録するということは、その関数がstaticになってないといかん。
いかんことはないだろうけど、メンバ関数をコールバック登録する方法がよくわからんので、やりたくない。

  1. Qtの場合、イベントが発生するときに「シグナルを送信」する。
  2. 送信されたシグナルは、「接続されたスロット」に通知される。
  3. シグナルとスロットの接続は動的に行い、メンバ関数(スロット)を指定する。

delegateみたいな感じだろうか。


シグナルの送信は、簡単だ。
メンバ関数定義はpublicとかprivateではなく「signals」に置く。
送信時は、キーワードemitを付けて呼び出すだけ。関数本体は書かない。

受けとるスロットも、似たようなものだ。
メンバ関数定義は「slots」に置く。これはpublic slotsやprivate slotsにできる。
シグナルとスロットの接続は、QObject::connect()を使う。

なんで関数本体がないシグナル定義が呼び出せるかというと、moc、というコンパイラが別にあるからだ。
メタオブジェクトコンパイラ、の略らしい。
「メタオブジェクト」というものがよくわからないが、Qt用のclass定義を読み込んでcppソースをつくるのだ。
その中で、シグナル関数も生成されている。

これは一例。

// SIGNAL 0
void Employee::salaryChanged(int _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}

mocが作るcppには、これ以外にもいろいろと生成している。
どうやってQt用のclass定義を見分けているかというと、おそらくQ_OBJECTマクロだ。
「Qt用のclass定義先頭に"Q_OBJECT"と書け」というルールなのだ。

mocがこそっとstaticメンバ関数を生成しているので、おそらくこんな流れになっているんじゃなかろうか。

  1. 「イベント送信」により、QMetaObject::activate()が呼ばれる
  2. activate()の引数で渡されたstaticMetaObjectには、mocが生成したstaticメンバ関数が書かれているので、それを呼び出す。
  3. staticメンバ関数内でうまいことやって、接続されたスロットを呼び出す。

staticメンバ関数を見ると、引数によって呼び先がシグナルかスロットかに分岐している。
シグナルを呼べるようになっているのは、シグナルとシグナルを接続できるようになっているからだろうか。

引数確認のためにstrcmp()で文字列化された接続先スロットを確認するなど、そこそこ軽くはない処理になっている。
オーバーヘッドをなくしたい場合は、プロファイラで比重が重たいところを探して、そこが安全であればチェックをコメントアウトしていく、というようなことをやっていかないかんのかもしれない。



こんな感じで、これからしばらくQtをやっていく。
目標は、こんな感じの会話ができること、だ。

依頼人:「○○なアプリを作ってください」
私:「・・・Qtで・・・作ることになるが」
依頼人:「もちろん構いません」
私:「報酬はスイス銀行に振り込んでくれ・・・」

いや、スイス銀行はどうでもいいのだ。口座持ってないし。
今の私は、アプリを作るプラットフォームを持っていない。
Androidで作ることもあるし、VC#で作ることもある。
でも、AndroidはJavaで苦手だし、VC#はWindows限定に近くなってしまう。
作って組込みアプリにするとなると、C/C++が望ましい。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。