サーチ…
前書き
備考
このトピックの公式文書はここにあります 。
小さな例
信号とスロットは、オブジェクト間の通信に使用されます。シグナルとスロットのメカニズムはQtの中心的な機能であり、おそらく他のフレームワークが提供する機能と最も異なる部分です。
最小限の例では、1つの信号、1つのスロット、1つの接続を持つクラスが必要です。
counter.h
#ifndef COUNTER_H
#define COUNTER_H
#include <QWidget>
#include <QDebug>
class Counter : public QWidget
{
/*
* All classes that contain signals or slots must mention Q_OBJECT
* at the top of their declaration.
* They must also derive (directly or indirectly) from QObject.
*/
Q_OBJECT
public:
Counter (QWidget *parent = 0): QWidget(parent)
{
m_value = 0;
/*
* The most important line: connect the signal to the slot.
*/
connect(this, &Counter::valueChanged, this, &Counter::printvalue);
}
void setValue(int value)
{
if (value != m_value) {
m_value = value;
/*
* The emit line emits the signal valueChanged() from
* the object, with the new value as argument.
*/
emit valueChanged(m_value);
}
}
public slots:
void printValue(int value)
{
qDebug() << "new value: " << value;
}
signals:
void valueChanged(int newValue);
private:
int m_value;
};
#endif
main
は新しい値を設定します。スロットがどのように呼び出されているかを確認し、値を出力することができます。
#include <QtGui>
#include "counter.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Counter counter;
counter.setValue(10);
counter.show();
return app.exec();
}
最後に、私たちのプロジェクトファイル:
SOURCES = \
main.cpp
HEADERS = \
counter.h
新しいQt5接続構文
SIGNAL
とSLOT
マクロを使用connect
従来のconnect
構文は、実行時に完全に機能します。ランタイムオーバーヘッド(バイナリサイズオーバーヘッドにもなります)があり、コンパイル時の正しさチェックはありません。新しい構文は両方の問題に対処します。例で構文をチェックする前に、特に何が起こるかを知っておくとよいでしょう。
家を建ててケーブルを接続したいとしましょう。これはまさにconnect関数がするものです。信号とスロットは、この接続を必要とするものです。要点は、1つの接続を行う場合は、さらに重複する接続に注意する必要があります。信号をスロットに接続するときはいつでも、信号が放射されるたびにスロット機能を呼び出すようコンパイラーに指示しようとしています。これはまさに何が起こるかです。
main.cppのサンプルは次のとおりです。
#include <QApplication>
#include <QDebug>
#include <QTimer>
inline void onTick()
{
qDebug() << "onTick()";
}
struct OnTimerTickListener {
void onTimerTick()
{
qDebug() << "OnTimerTickListener::onTimerTick()";
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
OnTimerTickListener listenerObject;
QTimer timer;
// Connecting to a non-member function
QObject::connect(&timer, &QTimer::timeout, onTick);
// Connecting to an object member method
QObject::connect(&timer, &QTimer::timeout, &listenerObject, &OnTimerTickListener::onTimerTick);
// Connecting to a lambda
QObject::connect(&timer, &QTimer::timeout, [](){
qDebug() << "lambda-onTick";
});
return app.exec();
}
ヒント:古いシンタックス( SIGNAL
/ SLOT
マクロ)では、スロットやシグナルを持つクラスに対してQtメタコンパイラ(MOC)を実行する必要があります。コーディングの観点からは、そのようなクラスにはQ_OBJECT
マクロ(このクラスでMOCを実行する必要性を示す)が必要であることを意味します。
一方、新しいシンタックスでは、シグナル用にはMOCが必要ですが、スロット用ではありません 。クラスにスロットとシグナルしか持たない場合は、 Q_OBJECT
マクロを持つ必要がないため、MOCを呼び出すことはできません。最終バイナリサイズを減らすだけでなく、コンパイル時間を短縮します(MOC呼び出しなし、 *_moc.cpp
ファイル)。
過負荷信号/スロットの接続
Qt5の新しい接続構文は、多くの点で優れていますが、過負荷信号とスロットを接続するという大きな弱点があります。コンパイラにオーバーロードを解決させるために、メンバ関数ポインタにstatic_cast
を使用する必要があります。(Qt 5.7から開始します) qOverload
とfriends:
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}
public slots:
void slot(const QString &string) {}
void slot(const int integer) {}
signals:
void signal(const QString &string) {}
void signal(const int integer) {}
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
// using pointers to make connect calls just a little simpler
MyObject *a = new MyObject;
MyObject *b = new MyObject;
// COMPILE ERROR! the compiler does not know which overloads to pick :(
QObject::connect(a, &MyObject::signal, b, &MyObject::slot);
// this works, now the compiler knows which overload to pick, it is very ugly and hard to remember though...
QObject::connect(
a,
static_cast<void(MyObject::*)(int)>(&MyObject::signal),
b,
static_cast<void(MyObject::*)(int)>(&MyObject::slot));
// ...so starting in Qt 5.7 we can use qOverload and friends:
// this requires C++14 enabled:
QObject::connect(
a,
qOverload<int>(&MyObject::signal),
b,
qOverload<int>(&MyObject::slot));
// this is slightly longer, but works in C++11:
QObject::connect(
a,
QOverload<int>::of(&MyObject::signal),
b,
QOverload<int>::of(&MyObject::slot));
// there are also qConstOverload/qNonConstOverload and QConstOverload/QNonConstOverload, the names should be self-explanatory
}
マルチウィンドウ信号スロット接続
信号とスロットを使った簡単なマルチウィンドウの例。
メインウィンドウビューを制御するMainWindowクラスがあります。ウェブサイトクラスによって制御される第2のウィンドウ。
2つのクラスが接続されているため、ウェブサイトウィンドウのボタンをクリックすると、MainWindowで何かが発生します(テキストラベルが変更されます)。
私はGitHubにある簡単な例を作った:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "website.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void changeText();
private slots:
void on_openButton_clicked();
private:
Ui::MainWindow *ui;
//You want to keep a pointer to a new Website window
Website* webWindow;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::changeText()
{
ui->text->setText("New Text");
delete webWindow;
}
void MainWindow::on_openButton_clicked()
{
webWindow = new Website();
QObject::connect(webWindow, SIGNAL(buttonPressed()), this, SLOT(changeText()));
webWindow->show();
}
website.h
#ifndef WEBSITE_H
#define WEBSITE_H
#include <QDialog>
namespace Ui {
class Website;
}
class Website : public QDialog
{
Q_OBJECT
public:
explicit Website(QWidget *parent = 0);
~Website();
signals:
void buttonPressed();
private slots:
void on_changeButton_clicked();
private:
Ui::Website *ui;
};
#endif // WEBSITE_H
website.cpp
#include "website.h"
#include "ui_website.h"
Website::Website(QWidget *parent) :
QDialog(parent),
ui(new Ui::Website)
{
ui->setupUi(this);
}
Website::~Website()
{
delete ui;
}
void Website::on_changeButton_clicked()
{
emit buttonPressed();
}
プロジェクト構成:
SOURCES += main.cpp\
mainwindow.cpp \
website.cpp
HEADERS += mainwindow.h \
website.h
FORMS += mainwindow.ui \
website.ui
Uisを構成すると考えてください:
- メインウィンドウ: "text"というラベルと "openButton"というボタン
- ウェブサイトウィンドウ:「changeButton」ボタン
したがって、キーポイントは、信号とスロットの間の接続と、ウィンドウポインタまたは参照の管理です。