【Qt】QSignalMapperは まいそうされます。


おことわり

この記事は次のブログからの転載です。

概要

Image from Gyazo

画像のような複数のUIの操作に応じて一つのUIを更新する処理は QSignalMapper が担ってきました。

しかし Qt5 では QSignalMapper は非推奨とされ、 ラムダ式 への置き換えが推奨されます。

そこで、実際にどのように置き換えていくかをここに記録します。

従来の QSignalMapper を用いた手法

    // legacy style signal mapping
    mapper = new QSignalMapper(this);
    QVector<QPushButton *> foobarButtons({
        ui.fooButton,
        ui.barButton,
        ui.foobarButton,
    });
    for (auto const &button : foobarButtons)
    {
        connect(button, SIGNAL(clicked()), mapper, SLOT(map()));
        mapper->setMapping(button, button->text());
    }
    connect(mapper, SIGNAL(mapped(QString)), this, SLOT(foobarLabelUpdate(QString)));

処理の流れは次の通りです:

  1. QSignalMapper を作成する。
  2. sender(button) から QSignalMapper へ connect をする。
  3. QSignalMapper::map() が実行されるとき、 QSignalMapper から送出する内容を登録する。
  4. QSignalMapper::mappped() から送出される内容を受け取る slot (foobarLabelUpdate) へ connect する。

前提として必要なことは2つ、 QSignalMapper のインスタンス該当の操作に対応できるSlot そして、くじけない心です。

ラムダ式を用いた手法

    // qt5 style signal mapping
    QVector<QPushButton *> fizzbuzzButtons({
        ui.fizzButton,
        ui.buzzButton,
        ui.fizzbuzzButton,
    });
    for (auto const &button : fizzbuzzButtons)
    {
        auto const &text = button->text();
        connect(button, &QPushButton::clicked, [=] { ui.fizzbuzzLabel->setText(text); });
    }

処理の流れは次の通りです:

  1. sender(button) からラムダ式へ connect をする。

もう少し言うと、[=] ではじまるラムダ式なので送出していた内容を変数textに格納するという準備をしています。

これは比較のためにQStringで揃えているだけですので、コメントで指摘いただきましたが、buttonそのものを渡すことでより簡潔に書けます。

    for (auto const &button : fizzbuzzButtons)
    {
        connect(button, &QPushButton::clicked, [=] { ui.fizzbuzzLabel->setText(button->text()); });
    }

非常にシンプルになりました。
これなら気軽に書いていけますね。

参考資料