Qt信号スロット使用方式

4428 ワード

QT信号スロット接続の書き方
次に例を示します.
    QPushButton *btn = new QPushButton;

    //    :    
    connect(btn, SIGNAL(clicked()), this, SLOT(close()));

    //    :Qt5    
    connect(btn, &QPushButton::clicked, this, &MainWindow::close);

    //    :lambda   
    connect(btn, &QPushButton::clicked, this, [&]() {
        this->close();
    });

方式は古い書き方で、コンパイル時に信号やスロットが存在しなくてもエラーは報告されませんが、実行時には無効で、C++という静的言語にとって、これは友好的ではなく、デバッグに不利です.
方式2 Qt 5の後に推薦する書き方、もしコンパイルする時信号あるいは溝が存在しないならばコンパイルすることができなくて通過することができなくて、コンパイルする時検査に相当して、間違いを犯しにくくて、また溝の書き方は直接public制御ドメインの下で書くことができて、必ずしもpublic slots:制御ドメインの下で書く必要はありません;また,スロットオブジェクトを省略するとqtcreatorはエラーを提示しないが,コンパイルは通過できない.
方式3はlambda式の書き方を採用しており、より便利で速い.パラメータ要件:信号のパラメータ数>=スロットのパラメータ数であり、前の同じ数のパラメータタイプが一致し、信号内の余分なパラメータは無視されます.
Lambdaについては、次の点に注意してください.
QTimer::singleShot(3000, /* this, */ [&]{
        this->close();
    });

connect(btn, &QPushButton::clicked, /* this, */ [&]() {
        this->close();
    });

上記の例を見ると、lambda式を使用する場合、スロットの受信者QObjectは省略して書くことができ、Qtは送信者と受信者が同じQObjectに属することをデフォルトにします.
    //connect to a functor
    template 
    static inline typename std::enable_if<:functionpointer>::ArgumentCount == -1, QMetaObject::Connection>::type
            connect(const typename QtPrivate::FunctionPointer::Object *sender, Func1 signal, Func2 slot)
    {
        return connect(sender, signal, sender, slot, Qt::DirectConnection);
    }

スロット関数受信者QObjectを省略する場合は、lambda内のメンバーのライフサイクルに注意する必要があります.例のsingleShotは、スロット関数が応答する前にthisが無効なポインタに破棄された場合、深刻な結果になります!!!
どうして?
connectの送信者と受信者のいずれかが破棄されると、このconnectはすでに切断されていることを知っています.受信者QObjectを省略すると、送信者と受信者は同じQObjectに属する.上記の例では、信号スロットconnect関連は依然として存在し、信号スロットは依然としてトリガーされるが、この場合thisは破棄される
Lambdaの使用説明コードは次のとおりです.
int main() { int a = 1; int b = 2;
auto func = [=, &b](int c)->int {return b += a + c;}; return 0; }
Lambda関数は関数であり、構文は次のように定義されています.
[capture](parameters) mutable ->return-type{statement}
1.[capture]:スナップリスト.スナップリストは常にLambda関数の先頭に表示されます.実際,[]はLambdaバルーンである.コンパイラは、この引数に基づいて、次のコードがLambda関数であるかどうかを判断します.スナップリストは、Lambda関数で使用するためにコンテキスト内の変数をスナップできます.
2.(parameters):パラメータリスト.通常の関数のパラメータリストと一致します.パラメータ伝達が不要な場合は、カッコ「()」とともに省略できます.
3.mutable:mutable修飾子.デフォルトでは、Lambda関数は常にconst関数であり、mutableは定数を取り消すことができます.この修飾子を使用する場合、パラメータリストは省略できません(パラメータが空であっても).
4->return-type:戻りタイプ.関数の戻りタイプをトレース戻りタイプとして宣言します.戻り値を必要としない場合には、記号"->"とともに省略することもできます.また、戻りタイプが明確な場合は、この部分を省略して、コンパイラに戻りタイプを導出させるようにしてもよい.
5.{statement}:関数体.内容は通常の関数と同じですが、パラメータのほかに、取得したすべての変数を使用できます.
通常の関数との最大の違いは、パラメータの使用に加えて、Lambda関数がキャプチャリストを使用してコンテキスト内のデータにアクセスできることです.具体的には、スナップリストには、コンテキスト内でLambdaで使用できるデータと、値で渡す方法または参照で渡す方法が記載されています.構文的には、[]にはスナップリストが含まれており、スナップリストは複数のスナップ項目で構成され、カンマで区切られています.スナップリストには、次のような形式があります.
1.[var]は値伝達方式が変数varを捕捉することを表す.2.[=]は値伝達方式がすべての親作用域を捕捉する変数(thisを含む)を表し、3.[&var]は参照伝達捕捉変数varを表し、4.[&]は参照伝達方式がすべての親作用域を捕捉する変数(thisを含む)を表し、5.[this]は値伝達方式が現在のthis針を捕捉することを表す.
親ドメイン、すなわちLambda関数を含む文ブロックについて述べたが、一般的にはLambdaを含む「{}」コードブロックである.上のスナップリストは、次のように組み合わせることもできます.
1.[=,&a,&b]は、伝達を参照して変数aおよびbを捕捉し、他のすべての変数を値伝達で捕捉することを表す.2.[&,a,this]は、変数aとthisを値伝達で捉え、伝達方式を参照して他のすべての変数を捕捉することを表す.
ただし、スナップリストでは変数の繰返しは許可されていません.次の例は典型的な繰り返しであり、コンパイル時期のエラーを引き起こす.例:
3.[=,a]ここではすべての変数を値伝達でスナップしたが、aを繰り返しスナップすると、エラーが報告される.4.[&,&this]ここで&はすべての変数を参照伝達でスナップし、thisをスナップするのも繰り返しです.
コードの例を次に示します.
  //        

  for(int  i=0;  i(windows.at(i)->widget());

      QString  text;

      //     9         ,  &%1 %2       ,           

      if(i<9){

          text  =  tr("&%1%2").arg(1+i)

          .arg(child->userFriendlyCurrentFile());

      }else{

          text  =  tr("%1%2").arg(1+i)

          .arg(child->userFriendlyCurrentFile());

      }

      //       ,      

      QAction  *action  =  ui->menuW->addAction(text);

      action->setCheckable(true);

      action->setChecked(child  ==  activeMdiChild());



      //   lambda   &     ,    i        

      connect(action,  &QAction::triggered,

      [=](){this->setActiveSubWindow(windows.at(i));});

  }