1.コントラスト
Qt 5以降、QTは、信号スロット接続を書き込む2つの異なる方法を提供します。文字列ベース(SIGNAL / SLOTは信号/スロットを文字列に変換します)接続構文と関数ポインターベースの接続構文です。どちらの文法にも長所と短所があります。次の表は、それらの違いをまとめたものです。
ストリング | 関数ポインタ | |
型式検査期間: | ランタイム | コンパイル時間 |
暗黙の型変換を実行できます | √ | |
信号をラムダ式に接続できます | √ | |
信号よりも多くのパラメータを使用して信号をスロットに接続できます(デフォルトのパラメータを使用) | √ | |
C ++関数をQML関数に接続できます | √ |
2つ目は、型チェックと暗黙的な型変換です。
文字列ベースの接続は、実行時に型チェックを実行します。これには3つの制限があります。
- 接続エラーは、プログラムの実行開始後にのみ検出できます。
- 信号とスロット間のパラメータの暗黙的な変換はできません。
- typedefと名前空間を解決できません。
文字列コンパレータはC ++タイプ情報にアクセスできないため、2と3が存在します。したがって、文字列の完全一致に依存します。
代わりに、コンパイラは関数ポインタに基づいて接続をチェックします。コンパイラーはコンパイル時にエラーをキャッチし、互換性のあるタイプ間の暗黙的な変換を可能にし、同じタイプの異なる名前を認識します。
3つ目は、ラムダ式との接続を確立する
関数ポインタベースの接続構文は、実際にはインラインスロットであるC ++ 11ラムダ式にシグナルを接続できます。この機能は、文字列ベースの構文では使用できません。
注:関数ポインターベースのリンク構文は、独立関数や通常のメンバー関数を含むすべての関数へのポインターを受け入れます。ただし、読みやすくするために、シグナルはスロット、ラムダ式、およびその他のシグナルにのみ接続する必要があります。
第4に、C ++オブジェクトをQMLオブジェクトに接続します
文字列ベースの構文はC ++オブジェクトをQMLオブジェクトに接続できますが、関数ポインタベースの構文は接続できません。これは、QMLタイプが実行時に解析されるため、C ++コンパイラには適していないためです。
以下の例では、QMLオブジェクトをクリックすると、C ++オブジェクトがメッセージを出力し、その逆も同様です。
QmlGui.qml:
Rectangle
{
width: 100; height: 100
signal qmlSignal(string sentMsg)
function qmlSlot(receivedMsg)
{
console.log("QML received: " + receivedMsg)
}
MouseArea
{
anchors.fill: parent
onClicked: qmlSignal("Hello from QML!")
}
}
class CppGui : public QWidget
{
Q_OBJECT
QPushButton *button;
signals:
void cppSignal(const QVariant& sentMsg) const;
public slots:
void cppSlot(const QString& receivedMsg) const
{
qDebug() << "C++ received:" << receivedMsg;
}
public:
CppGui(QWidget *parent = nullptr) : QWidget(parent)
{
button = new QPushButton("Click Me!", this);
connect(button, &QPushButton::clicked, [=]
{
emit cppSignal("Hello from C++!");
});
}
};
接続信号:
auto cppObj = new CppGui(this);
auto quickWidget = new QQuickWidget(QUrl("QmlGui.qml"), this);
auto qmlObj = quickWidget->rootObject();
// 连接QML信号到C++槽
connect(qmlObj, SIGNAL(qmlSignal(QString)),cppObj, SLOT(cppSlot(QString)));
// 连接C++信号到QML槽
connect(cppObj, SIGNAL(cppSignal(QVariant)),qmlObj, SLOT(qmlSlot(QVariant)));
注:QMLのすべてのJavaScript関数は、C ++のQVariant型にマップされるvar型パラメーターを使用します。
5、スロット内のデフォルトパラメータの数<信号内のパラメータの数
文字列ベースの接続構文は、スロット内のデフォルトパラメータの数<信号内のパラメータの数の解決策を提供します。スロットにデフォルトパラメータがある場合、これらのパラメータは信号から無視できます。信号パラメータがスロットパラメータよりも小さい場合、Qtはデフォルトのパラメータ値を使用してスロットを実行します。
関数ポインタに基づくリンクは、この機能をサポートしていません。関数ポインタに基づくリンクは、この制限を取り除くためにラムダ式リンクを使用する必要があります。
6つの頑丈な信号スロット
文字列構文に基づいて、パラメータタイプを明示的に指定できます。したがって、過負荷の信号またはスロットの目的のインスタンスは明確です。
関数ポインタ構文に基づいて、オーバーロードされたシグナルまたはスロットは、使用するインスタンスをコンパイラに指示するように強制する必要があります。
例:QLCDNumberにはいくつかのリロードスロットがあります。
- QLCDNumber :: display(int)
- QLCDNumber :: display(double)
- QLCDNumber :: display(QString)
関数ポインタに基づくオーバーロードのいくつかの形式(connect(obj1、address 1、obj2、address 2);):
auto slider = new QSlider(this);
auto lcd = new QLCDNumber(this);
connect(slider, &QSlider::valueChanged,lcd, static_cast<void (QLCDNumber::*)(int)>(&QLCDNumber::display));//函数的地址转成QLCDNumber类的函数指针可以指向的地址
void (QLCDNumber::*mySlot)(int) = &QLCDNumber::display;//指向QLCDNumber类的函数指针 = 成员函数的地址
connect(slider, &QSlider::valueChanged,lcd, mySlot);
//C++14以后才支持
connect(slider, &QSlider::valueChanged,lcd, qOverload<int>(&QLCDNumber::display));
1、自動qOverload(T functionPointer)
オーバーロードされた関数へのポインタを返します。テンプレートパラメータは、関数のパラメータタイプのリストです。functionPointerは関数へのポインターです(非メンバー関数も使用できます):
struct Foo {
void overloadedFunction();
void overloadedFunction(int, const QString &);
};
qOverload<>(&Foo::overloadedFunction) //返回指向void overloadedFunction()的地址
qOverload<int, const QString &>(&Foo::overloadedFunction)
2、auto qConstOverload(T memberFunctionPointer)
constメンバー関数へのポインターを返します(その後にconstを付けます):
3、auto qNonConstOverload(T memberFunctionPointer)
非constメンバー関数へのポインターを返します。
struct Foo {
void overloadedFunction(int, const QString &); //A
void overloadedFunction(int, const QString &) const; //B
};
qConstOverload<int, const QString &>(&Foo::overloadedFunction) //对应B
qNonConstOverload<int, const QString &>(&Foo::overloadedFunction) //对应A