1

まず第一に、見栄えのする質問で申し訳ありませんが、実際にはそうではありません。Foundation of qt development book を読んでいて、第 4 章を読みながら、著者は次の例を示して MDI ウィンドウの基本を説明しています。

MdiWindow::MdiWindow( QWidget *parent ) : QMainWindow( parent ) {
  setWindowTitle( tr( "MDI" ) );
  QWorkspace* workspace = new QWorkspace;
  setCentralWidget( workspace );
  connect( workspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(enableActions()));
  QSignalMapper* mapper = new QSignalMapper( this );

  //my problem is in this line
  connect( mapper, SIGNAL(mapped(QWidget*)), workspace, SLOT(setActiveWindow(QWidget*)) );

  createActions();
  createMenus();
  createToolbars();
  statusBar()->showMessage( tr("Done") );
  enableActions();
}

彼の説明のパラグラフは完全に私を避けました(それを理解するのに問題があるのは私ですか、それとも他の人ですか?):

次に、QSignalMapper というシグナル マッピング オブジェクトを作成して接続します。シグナル マッパーは、シグナルのソースを別のシグナルの引数に結び付けるために使用されます。この例では、[ウィンドウ] メニューの各ウィンドウに対応するメニュー項目のアクションが、実際のドキュメント ウィンドウに関連付けられています。アクションはマッパーに接続されます。トリガーされたシグナルがアクションによって発行されると、送信アクションは対応するドキュメント ウィンドウの QWidget* に関連付けられています。このポインターは、シグナル マッピング オブジェクトによって発行されるマップされた (QWidget*) シグナルの引数として使用されます。

私の質問:シグナルマッパークラスとは何か、それがどのように使用され、上記の例でどのような機能を果たしているのか、まだわかりませんか?. 上記のパラグラフを簡単な用語を使って説明してもらえますか? また、マッパークラスの基本を簡単な例で教えていただければ幸いです。おそらく素人の言葉で?

PS : MDI ウィンドウがあり、メニューの変更を行うと混乱します (アクションは無効/有効になります)。たとえば、ある特定のドキュメントには「ファイル/閉じる」メニューがあり、他のドキュメントには「ファイル/リマッパー」があるとします。

4

2 に答える 2

4

QSignalMapper、オプションのパラメーターを使用して信号を再送信するために使用されます。言い換えれば(ドキュメントから):

このクラスは、パラメーターのないシグナルのセットを収集し、シグナルを送信したオブジェクトに対応する整数、文字列、またはウィジェット パラメーターを使用してそれらを再送信します。

良い例(ドキュメントからも-見てください)は次のように設定されています:

ボタンのグループ (ツール パレットなど) を含むカスタム ウィジェットを作成するとします。1 つの方法は、各ボタンの clicked() シグナルを独自のカスタム スロットに接続することです。しかし、この例では、すべてのボタンを 1 つのスロットに接続し、クリックされたボタンによってスロットをパラメーター化します。

たとえばButtonWidget、カスタム シグナルを持つクラスにカプセル化された多数のボタンがあるとしますvoid clicked(const QString &text)。定義は次のとおりです。

class ButtonWidget : public QWidget {
  Q_OBJECT

public:
  ButtonWidget(QStringList texts, QWidget *parent = 0);

signals:
  void clicked(const QString &text);

private:
  QSignalMapper *signalMapper;
};

コンストラクタは、次のように定義できます。

ButtonWidget::ButtonWidget(QStringList texts, QWidget *parent)
  : QWidget(parent)
{
  signalMapper = new QSignalMapper(this);

  QGridLayout *gridLayout = new QGridLayout;
  for (int i = 0; i < texts.size(); ++i) {
    QPushButton *button = new QPushButton(texts[i]);
    connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
    signalMapper->setMapping(button, texts[i]);
    gridLayout->addWidget(button, i / 3, i % 3);
  }

  connect(signalMapper, SIGNAL(mapped(const QString &)),
          this, SIGNAL(clicked(const QString &)));

  setLayout(gridLayout);
}

それで、ここで何が起こりますか?グリッド レイアウトと type のボタンを作成しますQPushButton。これらのそれぞれのclicked()信号は、信号マッパーに接続されます。

使用する力の 1 つはQSignalMapper、再送信されたシグナルに引数を渡すことができることです。この例では、各ボタンは (シグナルの定義により) 異なるテキストを出力する必要があるため、setMapping()メソッドを使用してこれを設定します。

あとは、シグナル マッパーをクラスのシグナルにマップするだけです。

connect(signalMapper, SIGNAL(mapped(const QString &)),
        this, SIGNAL(clicked(const QString &)));

と呼ばれるテストクラスがあると仮定すると、TestClass次のButtonWidgetように使用できます。

TestClass::TestClass() {
  widget = new ButtonWidget(QStringList() << "Foo" << "Bar");
  connect(widget, SIGNAL(clicked(const QString &)),
          this, SLOT(onButtonClicked(const QString &)));
}

void TestClass::onButtonClicked(const QString &btnText) {
  if (btnText == "Foo") {
    // Do stuff.
  }
  else {
    // Or something else.   
  }
}

この方法でシグナル マッパーを使用すると、すべてのボタンとクリックされたシグナルを宣言して管理する必要がなくなり、1 つのシグナル pr. ButtonWidget.

肝心なのは、シグナルマッパーは複数のシグナルをバンドルするのに最適であり、それらを再送信するときにパラメーターを設定することもできるということです. の使用法についてある程度の直感が得られたことを願っていますQSignalMapper


サンプルコード

説明(あなたの「パラ」)は、すべてのアクションがそれぞれ個別に特定のにマップされていると述べていますQWidget*。アクションをトリガーすると、それぞれが のスロットにQWidget*渡され、ウィジェットがアクティブになります。QWorkspace::setActiveWindow(QWidget*)workspace

また、アクションからウィジェットへのマッピングは、コードのどこかで行う必要があることに注意してください。createActions()またはenableActions()おそらくで行われていると思います。

于 2012-09-29T15:54:39.220 に答える
1

QSignalMapperを使用すると、必要なときにシグナルに情報を追加できます。このオブジェクトは内部的に のようなマップを持っていますQMap<QObject*,QVariant>。次に、オブジェクトをそれに接続し、スロットが呼び出されると、関連付けられた値で信号を再送信します。

ワークフロー:

mySignalMapper:
    [ obj1 -> 42       ]
    [ obj2 -> "obiwan" ]
    [ obj3 -> myWidget ]

connect(obj1,mySignal,mySignalMapper,SLOT(map())); // idem for obj2 and obj3

(obj2 emits "mySignal")
-> (mySignalMapper::map slot is called)
-> (sender() == obj2, associated data = "obiwan")
-> (mySignalMapper emits mapped("obiwan"))

より詳細な例を追加するつもりでしたが、Morten Kristensen は私よりも速かったです ;)

于 2012-09-29T16:00:00.493 に答える