10

C++ に Qt アプリケーションがあり、スロットを QPushButton に割り当てたいと考えています。しかし、複数の QPushButton が同様のことを行っているため、いくつかの引数を渡したいので、1 つの関数が必要ですが、パラメーターが含まれていますが、Qt はこのようなスロットがないと言い続けます。誰かが理由と方法を教えてもらえますか?

前もって感謝します

私が持っている .h ファイルでは: (最初は非公開でしたが、問題の検索で変更しました)

public slots:
    void handleButton(int row, int col);

次に、.cpp で:

void fieldWindow::handleButton(int row, int col){
    cout << row << " " << col << endl;
}

そして再び同じ.cppで:

connect(this->buttonsField[i][j], SIGNAL(released()), this, SLOT(handleButton(i,j)));

これは 2 つのネストされたループで行われるためi、 と jは明確に定義されています。

そして私のエラーは次のとおりです。

QObject::connect: No such slot fieldWindow::handleButton(i,j) in ..\Proj1\fieldwindow.cpp:41
QObject::connect:  (receiver name: 'fieldWindow')

私は言うべきインターネットで何かを読みましたhandleButton(int, int);が、どのように引数を渡す必要がありますか?

4

1 に答える 1

15

悲しいことに、Qt シグナル スロット接続は、シグナルが呼び出されたときにスロットに渡される引数を受け入れません。これは、シグナル自体がこれらの引数を提供する場合にのみ機能しますが、それらをconnectステートメントに追加することはできません。

しかし、これをしたいのはあなただけではないので、Qtにはあなたが望むほとんどのことをするクラスがあります: QSignalMapper. このクラスのインスタンスは、シグナルスロット接続の「プロキシ」として使用できます。(複数の) ボタンをこのクラスのスロットに接続し、このクラスのシグナルをターゲットスロットに接続します。次に、各「送信者」インスタンス(あなたの場合はボタン)について、呼び出されたスロットに追加する値をクラスに伝えることができます。例:

QPushButton * button1 = ...;
QPushButton * button2 = ...;

QSignalMapper mapper;

connect(button1, SIGNAL(released()), &mapper, SLOT(map()));
mapper.setMapping(button1, 42); // Number to be passed in the slot

connect(button2, SIGNAL(released()), &mapper, SLOT(map()));
mapper.setMapping(button2, 1337); // Number to be passed in the slot

connect(&mapper, SIGNAL(mapped(int)), this, SLOT(handleButton(int)));

悲しいことに、ご覧のとおり、このクラスは1 つのパラメーターしか処理できません。intあなたの場合は、別の方法を選択する必要があります(単一のパラメーターを使用して同様の問題が再び発生した場合に備えて、上記で説明しました)。

sender()あなたの問題に合った代替手段は、スロット内に依存することです。次のようなデータ構造でマッピングを覚えておいてください

QMap<QObject*,int> rows;
QMap<QObject*,int> cols;

引数を取らないスロット内のものにアクセスします。

void fieldWindow::handleButton(){
    int row = rows[sender()];
    int col = cols[sender()];
    cout << row << " " << col << endl;
}

もちろん、UI を初期化するときは、これらのマップに適切な値を設定する必要があります。または、既存の配列でボタンを検索することもできますbuttonsField

Qt5 および C++11 以降、別の方法が存在します。スロットの代わりに、ラムダ関数でシグナルを処理できます。これは次のようになります (信号は新しい構文を使用して名前が付けられます)。

connect(this->buttonsField[i][j], &QPushButton::released, [=]{
    handleButton(i, j);
});

ラムダ構文が気に入らない場合は、標準ライブラリのヘルパーを使用してラムダの代わりにファンクターを作成するか、独自のファンクター クラスを作成することもできますが、個人的にはラムダが非常に読みやすいと思います。

于 2014-01-16T00:27:40.043 に答える