16

Qtで信号とスロットがどのように使用されているかを完全に把握するのに少し苦労しています。それは本当に基本的なことだと確信していますが、今日はそれを理解できていません。

私はこのようなウィジェットのセットを持っています:

MainWindow-> StackedWidget-> ChildForms

ここでの考え方は、子ウィジェットにいくつかのアクションがあり、スタックされたウィジェットに別のページを表示させるというものです。

それで、それを正しく理解していれば、信号とスロットを接続する方法はconnect()、オブジェクトを認識しているスコープで使用することだと思いましたが、私が何とか機能させることができたのは、この方法ではありません。現時点では、子フォームでparentWidget()を使用してStackedWidgetのスロットにアクセスしていますが、親に関する情報を子に提供しているため、あまり満足していません。

void TaskSelectionForm::setButtonMappings()
{
    // Set up a mapping between the buttons and the pages
    QSignalMapper *mapper = new QSignalMapper(this);
    connect(mapper, SIGNAL(mapped(int)), parentWidget(), SLOT(setCurrentIndex(int)));

    mapper->setMapping(ui->utilitiesButton, 2); // Value of the index
    connect(ui->utilitiesButton, SIGNAL(clicked()), mapper, SLOT(map()));
}

しかし、これをどのように実行して接続する必要があるのか​​、私にはよくわかりません。各レベルに信号があり、ツリーを介して放射する必要がありますか?

4

2 に答える 2

22

信号スロット理論のビット

信号スロット接続は、QObject間の親子関係を認識せず、そのような関係は重要ではありません。オブジェクトを子、兄弟、親、さらには別の階層にあるQObjectに接続したり、親も子も持たない単独のQObjectに自由に接続できます。それは問題ではありません。

信号スロット接続は、QObjectの特定のインスタンスの信号をQObjectの別のインスタンスのスロットに接続します。connectメソッドを使用するには、送信側QObjectのインスタンスと受信側QObjectのインスタンスへのポインターが必要です。次に、静的を使用しますQObject::connect(sender, SIGNAL(...), receiver, SLOT(...))。これらの接続は、送信者と受信者の間にある階層とは何の関係もありません。

シグナルをシグナルに接続して転送することもできます。たとえば、プライベートUI要素からクラスのAPIの一部であるシグナルに転送します。スロットをスロットに接続することはできません。これは、めったに使用されない場合に、実行時のオーバーヘッドが少し発生するためです。オーバーヘッドはbool、QObjectPrivateの追加メンバーと、失敗したif (bool)テストになります。スロットをスロットに転送する場合は、少なくとも2つの方法があります。

  1. ソーススロットで信号を発信し、その信号を宛先スロットに接続します。

  2. ソーススロットに接続されているすべての信号のリストを取得し、それを繰り返して、ターゲットスロットに接続します。さらなる信号がソーススロットに接続または切断されたときに、そのような接続を維持する簡単な方法はありません。残念ながら、QObjectには保護された機能しかなく、シグナルはありません。そのため、そのようなシグナルを発するようにconnectNotify(const char*)変更しない限り、QObjectに接続することはできません。src/corelib/kernel/qobject[.cpp,_p.h,.h]本当に必要な場合は、Qtソースを変更するだけで、結局のところ、理由があってアクセスできます。Qtを変更せずにvtableをハッキングすることは可能ですが、明らかな理由からお勧めできません。

答え

以下は、あなたがやりたいことをする方法を示す自己完結型の例です。過去にQtで行ったさまざまな実験から、かなりの数の質問に対する回答があります。テストコードに関しては、私は群れです。起動するのはすべてSSCCEです:)

// https://github.com/KubaO/stackoverflown/tree/master/questions/signal-slot-hierarchy-10783656
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif

class Window : public QWidget
{
   QSignalMapper m_mapper;
   QStackedLayout m_stack{this};
   QWidget      m_page1,                  m_page2;
   QHBoxLayout  m_layout1{&m_page1},      m_layout2{&m_page2};
   QLabel       m_label1{"Page 1"},       m_label2{"Page 2"};
   QPushButton  m_button1{"Show Page 2"}, m_button2{"Show Page 1"};
public:
   Window(QWidget * parent = {}) : QWidget(parent) {
      // the mapper tells the stack which page to switch to
      connect(&m_mapper, SIGNAL(mapped(int)), &m_stack, SLOT(setCurrentIndex(int)));

      // Page 1
      m_layout1.addWidget(&m_label1);
      m_layout1.addWidget(&m_button1);
      // tell the mapper to map signals coming from this button to integer 1 (index of page 2)
      m_mapper.setMapping(&m_button1, 1);
      // when the button is clicked, the mapper will do its mapping and emit the mapped() signal
      connect(&m_button1, SIGNAL(clicked()), &m_mapper, SLOT(map()));
      m_stack.addWidget(&m_page1);

      // Page 2
      m_layout2.addWidget(&m_label2);
      m_layout2.addWidget(&m_button2);
      // tell the mapper to map signals coming from this button to integer 0 (index of page 1)
      m_mapper.setMapping(&m_button2, 0);
      connect(&m_button2, SIGNAL(clicked()), &m_mapper, SLOT(map()));
      m_stack.addWidget(&m_page2);
   }
};

int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   Window w;
   w.show();
   return a.exec();
}
于 2012-05-31T21:49:48.350 に答える
0
Connect(stackedwidget->currentactivewidget,SIGNAL(OnAction()),this,SLOT(PrivateSlot()));

PrivateSlot()プライベートに宣言されたスロットです。したがって、この関数では、コードを追加して、currentactivewidgetによって生成されたアクションに対応するstackedwidgetのページを変更できます。

繰り返しますが、本当に信号を階層に渡したい場合はpublicsignal()、プライベートスロット関数の最後にを発行します。

Connect(this,SIGNAL(publicsignal()),Parentwidgetofstackedwidget(here mainwindow),SLOT(mainwindow_slot()));
于 2012-05-28T11:23:07.017 に答える