MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Qtの基礎 - シグナルとスロットのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Qtの基礎 - シグナルとスロット
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == シグナルおよびスロットの詳細は、以下のWebサイトを参照すること。<br> https://blog.qt.io/jp/2010/07/20/create-signals-and-slots-2<br> <br><br> == connect関数 == ==== Qt::ConnectionType ==== <code>connect</code>関数の<code>Qt::ConnectionType</code>の設定により動作が異なる。<br> <center> {| class="wikitable" | style="background-color:#fefefe;" |- ! style="background-color:#66CCFF;" | 接続タイプ(定数) ! style="background-color:#66CCFF;" | 動作 |- | Qt::AutoConnection || デフォルトの設定である。<br>SenderとReceiverが同じスレッドに存在する場合は、<code>Qt::DriectConnection</code>が使用される。<br>それ以外の場合は、<code>Qt::QueuedConnection</code>が使用される。<br><br>接続タイプはシグナルを<code>emit</code>する時に決定する。 |- | Qt::DriectConnection || シグナルを呼び出したスレッドから対象のスロットを呼び出す。(同期呼び出し) |- | Qt::QueuedConnection || Receiverのスレッド上でスロット関数が呼び出される。<br>シグナルはReceiver側のキューに入れられて、Receiverのイベントルーパーからスロット関数が呼び出される。(非同期呼び出し) |- | Qt::BlockingQueuedConnection || 基本的な動作は、Qt::QueuedConnectionと同様であるが、<br>シグナルの呼び出した側は、受信側のスロットの実行終了を待ち合わせる。<br><br><u>多用するとデッドロックを招きやすくなる。</u><br><u>例えば、Receiver側がSender側と同じスレッドに存在する場合には、必ず、デッドロックすることに注意する。</u> |- | Qt::UniqueConnection || 他の接続と組み合わせてビットORで設定する接続タイプである。<br>この設定が指定されている場合、オブジェクト間のシグナルとスロット、または、シグナルとシグナルの接続の組み合わせは1度しかできなくなる。<br>2つ以上同じシグナル・スロットの組み合わせで<code>connect</code>関数を実行した場合、<code>connect</code>関数は失敗する。<br><br>この設定は、Qt 4.6で追加された。 |} </center> <br> ==== connect関数 ==== <code>connect</code>関数は大きく分けて、2種類、細かく分けて4種類の種類が存在する。<br> <center> {| class="wikitable" | style="background-color:#fefefe;" |- ! style="background-color:#66CCFF;" | connect関数のシンタックス ! style="background-color:#66CCFF;" | スタイルの呼称 |- | Stringベース || Qt 4スタイル |- | rowspan=3 | Functorベース | Qt 5スタイル |- | Lambdaスタイル 1 |- | Lambdaスタイル 2 |} </center> <br> <syntaxhighlight lang="c++"> // Qt 4スタイルのconnect関数の形式 QMetaObject::Connection QObject::connect(Senderのポインタ, SIGNAL(シグナルの関数名(引数の型, ...)), Receiverのポインタ, SLOT(スロットの関数名(引数の型, ...)), Qt::ConnectionType type = Qt::AutoConnection) // 例. connect(sender, SIGNAL(value3Changed(int)), receiver, SLOT(setValue3(int))); // Qt 5スタイルのconnect関数の形式 QMetaObject::Connection QObject::connect(Senderのポインタ, &シグナルのクラス名::シグナルの関数名, Receiverのポインタ, &スロットのクラス名::スロットの関数名, Qt::ConnectionType type = Qt::AutoConnection) // 例. connect(sender, &Sender::value3Changed, receiver, &Receiver::setValue3); </syntaxhighlight> <br> <code>connect</code>関数の第2引数と第4引数において、Qt 4スタイルでは<code>SIGNAL</code>、<code>SLOT</code>というマクロを使用する。<br> このマクロは、Qt側で文字列(const char *signalのように)に変換される。<br> Qt 5スタイルと異なる点を、以下に示す。<br> * マクロの有無 * クラス名を記述するかどうか * 仮引数を明示的に記述するかどうか <br> <syntaxhighlight lang="c++"> // Lambdaスタイル 1のconnect関数の形式 QMetaObject::Connection connect(Senderのポインタ, &Senderのクラス名::シグナルの関数名, [=]() { 処理1; 処理2; ...; }); // 例. connect(sender, &Sender::valueChanged, [=]() { qDebug() << "Lambda Style1 signal received."; }); // Lambdaスタイル 2のconnect関数の形式 QMetaObject::Connection connect(Senderのポインタ, &Senderのクラス名::シグナルの関数名, コンテキストオブジェクト, [=]() { 処理1; 処理2; ...; }, Qt::QueuedConnection); // 例. connect(sender, &MyObject1::valueChanged, this, [=]() { qDebug() << "Lambda Style2 signal received."; }, Qt::QueuedConnection); </syntaxhighlight> <br> Lambda形式は、Receiverのスロット関数を作成しなくてよいため、シグナルが発生しているかどうかログを出力する時に便利である。<br> <br> Lambdaスタイル 1は、引数に<code>Qt::ConnectionType</code>が無い。<br> また、<code>Qt::ConnectionType</code>が<code>Qt::DirectConnection</code>固定となる。<br> つまり、SenderとReceiverが同一スレッドで動作することが前提となる。<br> <code>send</code>関数により、Senderを取得することもできない。<br> <br> Lambdaスタイル 2は、Qt 5.2で追加されたシンタックスである。<br> Lambdaスタイル 1と比較すると、第3引数にコンテキストが追加されて、第5引数に<code>Qt::ConnectionType</code>が追加されている。<br> <code>Qt::ConnectionType</code>が指定できるため、<code>Qt::DirectConnection</code>以外の動作も可能である。<br> また、<code>QObject::sender</code>関数も使用できる。<br> <br> 上記のLambdaスタイル 1およびLambdaスタイル 2の例では、ラムダ式に<code>キャプチャ式 [=]</code>を使用しているが、<code>キャプチャ式 [=]</code>以外のキャプチャ記法も使用できる。<br> <br> <center> {| class="wikitable" | style="background-color:#fefefe;" |+ StringベースとFunctorベースの比較 |- ! style="background-color:#66CCFF;width:50%;" | ! style="background-color:#66CCFF;width:25%;" | Stringベース ! style="background-color:#66CCFF;width:25%;" | Functorベース |- | 型チェックのタイミング | style="text-align: center;" | 実行時 | style="text-align: center;" | コンパイル時 |- | 暗黙の型変換 | style="text-align: center;" | 不可 | style="text-align: center;" | 可能 |- | シグナルをラムダ式で接続できる | style="text-align: center;" | 不可 | style="text-align: center;" | 可能 |- | シグナルより多くの引数を持つスロットに<br>シグナルを接続できる | style="text-align: center;" | 可能 | style="text-align: center;" | 不可 |- | QMLに接続できる | style="text-align: center;" | 可能 | style="text-align: center;" | 可能 |} </center> <br><br> ==シグナルとスロット == connect関数を使用して、シグナルとスロットの設定を行う。<br> <syntaxhighlight lang="c++"> connect(sender, SIGNAL(signal), receiver, SLOT(slot)); </syntaxhighlight> <br> 以下に、connenct関数の引数の意味を記載する。<br> * sender *: 信号が発生するコントロールIDまたはクラスのアドレスを渡す。 * SIGNAL(signal) *: signalに信号とする関数名を渡す。 *: 例: プッシュボタンの場合、<code>SIGNAL(clicked())</code>と記述する。 * receiver *: 信号を受信するコントロールIDまたはクラスのアドレスを渡す。 * SLOT(slot) *: 信号を受信した時に呼び出す関数名を渡す。 <br><br> == connect関数の使用方法 == <syntaxhighlight lang="c++"> #include "mainwindow.h" #include <QApplication> #include <QPushButton> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton* button = new QPushButton("Quit"); QObject::connect(button, SIGNAL(clicked()), &app, SLOT(quit())); button->show(); return app.exec(); } </syntaxhighlight> <br><br> == 静的メンバ関数のconnect == 静的メンバ関数は、インスタンスを生成せずに実行することができる。<br> 通常のメンバ関数の呼び出しと同様、thisからシグナルを発信して、thisでシグナルを受ければよい。<br> <br> また、送信側と受信側の両方がthisの場合、受信側インスタンスの指定を省略できるconnectのオーバーロード関数も存在する。<br> <br> 以下の例では、コンストラクタでシグナルとスロットを接続して、画面が表示された時、showEventメソッドでシグナルをemitしている。<br> また、送信側のクラスのインスタンスは生成していない。 <syntaxhighlight lang="c++"> // MainWindow.cpp #include "MainWindow.h" #include "ui_MainWindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); connect(this, &MainWindow::testSignal1, this, &QObjectEx::staticSlot); connect(this, &MainWindow::testSignal2, this, &QObjectEx::staticSlot); } MainWindow::~MainWindow() { delete ui; } void MainWindow::showEvent(QShowEvent *event) { QMainWindow::showEvent(event); emit testSignal1(10); emit testSignal2(20); } </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // MainWindow.h #pragma once #include <QMainWindow> #include "QObjectEx.h" namespace Ui {class MainWindow;} class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); signals: void testSignal1(int); void testSignal2(int); protected: void showEvent(QShowEvent *) override; private: Ui::MainWindow *ui; }; </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // QObjectEx.h #pragma once #include <QObject> class QObjectEx : public QObject { Q_OBJECT public slots: static void staticSlot(int i) { qDebug() << i; } }; </syntaxhighlight> <br><br> == Qt Designerで設定したシグナルおよびスロット == Qt Designerで設定したシグナルおよびスロットは、<code>connect</code>関数を使用せずに呼び出すことができる。<br> <br> ソースコード上で<code>connect</code>関数を使用せずにスロット関数が呼び出される理由を以下に示す。<br> まず、<code>QWidget</code>クラスや<code>QMainWindow</code>クラス等を継承した派生クラスにおいて、コンストラクタに自動生成されるソースコードで、以下の記述がある。<br> ui->setupUi(this); <br> 次に、<code>setupUi</code>メソッドの定義の最後に、以下の記述がある。<br> 以下に示す<code>QMetaObject::connectSlotsByName</code>メソッドは、オブジェクト(引数)が持つ全てのスロットに対して、<br> <code>on_<子オブジェクト名>_<子オブジェクトのシグナル名></code>を満たすスロット名の存在を確認する。<br> <syntaxhighlight lang="c++"> void setupUi(QMainWindow *MainWindow) { // ...略 QMetaObject::connectSlotsByName(MainWindow); } </syntaxhighlight> <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:Qt]]
Qtの基礎 - シグナルとスロット
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse