Qt5の信号とスロット

Qt5 alphaは光を見ました。 この記事では、取り組んだ機能の1つについて説明します。これは、信号とスロットの新しい構文です。



前の構文



これは通常、信号とスロットを接続する方法です。



connect(sender, SIGNAL(valueChanged(QString,QString)), receiver, SLOT(updateValue(QString)) );
      
      





実際、 SIGNAL



およびSLOT



マクロは引数を文字列に変換します。 次に、 QObject::connect()



は、これらの行をmoc



ユーティリティによってコンパイルされたイントロスペクションデータと比較します。



この構文の問題は何ですか?


一般にすべてがうまく機能するという事実にもかかわらず、まだいくつかの不便さがあります:





新しい構文:関数ポインターの使用



今後のQt5は代替構文をサポートします。 上記のアプローチに加えて、信号とスロットを接続するこの新しい方法を使用できます。



 connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue );
      
      





どちらが美しいかは好みの問題です。 しかし、新しいオプションに慣れるのは非常に簡単です。



次に、それがもたらす利点を検討します。



コンパイル時に確認する


シグナルまたはスロットの名前を間違えた場合、またはスロットの引数がシグナルの引数と一致しない場合、コンパイルエラーが発生します。 これにより、リファクタリング後の時間を節約できます。



さらに、 static_assert



、引数が一致しない場合やQ_OBJECT



スキップされる場合に明確なエラーを表示するためstatic_assert



使用されました。



引数型の自動キャスト


これで、typedefまたは名前空間の使用を恐れることなく、暗黙的なキャストが可能な場合、他の型の引数を受け入れるスロットに信号を接続できます。



次の例では、パラメーターとしてQString



を受け入れる信号をQVariant



を受け入れるスロットに接続します。 QVariant



QString



を受け入れる暗黙的なコンストラクタがあるため、これは問題なく機能します。



 class Test : public QObject { Q_OBJECT public: Test() { connect(this, &Test::someSignal, this, &Test::someSlot); } signals: void someSignal(const QString &); public: void someSlot(const QVariant &); };
      
      





信号を任意の機能に接続します


前の例でsomeSlot



たように、 someSlot



は、 slot



なしの単純なパブリックメソッドとして宣言されました。 Qtはスロットを直接呼び出すことができ、このためにイントロスペクションを必要としなくなりました。 (信号にはまだ必要ですが)



しかし今では、sinalを任意の関数またはファンクターに接続することもできます。



 static void someFunction() { qDebug() << "pressed"; } // ... somewhere else QObject::connect(button, &QPushButton::clicked, someFunction);
      
      





これは、boostまたはtr1 :: bindと組み合わせて非常に強力な機能になることができます。



C ++ 11の無名関数


以前に説明されたすべては、古いC ++ 98で動作します。 ただし、C ++ 11をサポートするコンパイラを使用する場合は、新しい言語機能を使用することを強くお勧めします。 ラムダ式は、少なくともMSVC 2010、GCC 4.5、clang 3.1でサポートされています。 最後の2つについては、フラグとして-std=c++0x



を指定する必要があります。



これで、次のコードを記述できます。



 void MyWindow::saveDocumentAs() { QFileDialog *dlg = new QFileDialog(); dlg->open(); QObject::connect(dlg, &QDialog::finished, [=](int result) { if (result) { QFile file(dlg->selectedFiles().first()); // ... save document here ... } dlg->deleteLater(); }); }
      
      





これにより、非同期コードの作成が非常に簡単になります。



All Articles