信号スロット理論のビット
信号スロット接続は、QObject間の親子関係を認識せず、そのような関係は重要ではありません。オブジェクトを子、兄弟、親、さらには別の階層にあるQObjectに接続したり、親も子も持たない単独のQObjectに自由に接続できます。それは問題ではありません。
信号スロット接続は、QObjectの特定のインスタンスの信号をQObjectの別のインスタンスのスロットに接続します。connectメソッドを使用するには、送信側QObjectのインスタンスと受信側QObjectのインスタンスへのポインターが必要です。次に、静的を使用しますQObject::connect(sender, SIGNAL(...), receiver, SLOT(...))
。これらの接続は、送信者と受信者の間にある階層とは何の関係もありません。
シグナルをシグナルに接続して転送することもできます。たとえば、プライベートUI要素からクラスのAPIの一部であるシグナルに転送します。スロットをスロットに接続することはできません。これは、めったに使用されない場合に、実行時のオーバーヘッドが少し発生するためです。オーバーヘッドはbool
、QObjectPrivateの追加メンバーと、失敗したif (bool)
テストになります。スロットをスロットに転送する場合は、少なくとも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();
}