signals and slots in multilayered UI widgets

旧街凉风 提交于 2019-11-27 05:38:46

Usually the enclosing widget encapsulates the widgets inside it and provides a higher-level interface. E.g., if W3 contains several widgets that need to be enabled/disabled depending on some state, W3 would manage that state, provide API for it and enable/disable widgets accordingly. So usually there is no need to go directly from W1 to W3.

If the widgets don't know about each other (e.g. b/c W1 is a generic container widget that can embed anything), then the one who assembles the UI, knowing all involved widgets, should do the connection.

I don't know what you mean by "qApp signal", but that sounds too much like on central object being connected to everything, which of course isn't good design either.

Maybe you have a specific example you had in mind?

The approach we use here is that "the shell" makes the connections.

The shell is an object that knows about all the widgets involved. In this case, W1, W2, and W3. Usually it is the code that assembles the user interface.

If the shell doesn't know about W3 (because W3 is an implementation detail, for example) then W3's "owner" should make the connection and so on.

You might set name to widgets and then discover them anywhere:

for(auto w_ptr: qApp->allWidgets())
    if(w_ptr->objectName() == "QObject anywhere")
        connect(...)

or in the parent widget:

if(QPushButton* o = findChild<QPushButton*>("QPushButton with name"))
    connect(...)

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget wdgt;
    wdgt.setWindowTitle("wdgt");
    wdgt.setObjectName("wdgt");
    wdgt.show();

    Widget w;
    w.show();

    return a.exec();
}

widget.cpp

#include <qlayout>
#include <qpushButton>
#include <qdebug>
#include <qapplication>

#include "widget.h"
#include "connect_by_name.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle("Widget");

    m_label->setFrameShape(QFrame::Box);

    QHBoxLayout * hl{new QHBoxLayout{}};

    hl->addWidget(m_label);
    hl->addWidget(new connect_by_name{});
    setLayout(hl);

    connect_to_unique_pb();
}

void Widget
::connect_to_unique_pb() {
    if(QPushButton * pb_ptr
            = findChild<QPushButton*>("unique_pb"))
    {
        connect(pb_ptr,  &QPushButton::pressed,
                m_label, &QLabel::clear);
        connect(pb_ptr,  &QPushButton::released,
                this,    &Widget::pb_relased);
    }
    else
    {
        qDebug() << "The push button not found.";
    }
}

void Widget
::pb_relased() {
    m_label->setText("button not pressed");
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <qwidget>
#include <QLabel>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);

public slots:
    void pb_relased();

private:
    void connect_to_unique_pb();

private:
    QLabel * m_label{new QLabel{"button not pressed"}};
};

#endif // WIDGET_H

connect_by_name.cpp

#include <qapplication>
#include <qdebug>
#include <qwidget>

#include "connect_by_name.h"
#include "widget.h"

connect_by_name
::connect_by_name(QWidget *parent) :
    QWidget(parent)
{
    m_pb->setObjectName("unique_pb");
    m_hl->addWidget(m_pb);
    connect_to_unique_widget();
}

void connect_by_name
::connect_to_unique_widget() {
    for(auto w_ptr: qApp->allWidgets())
        if(w_ptr->objectName() == "wdgt") {
            connect(m_pb,  &QPushButton::pressed,
                    w_ptr, &QWidget::hide);
            connect(m_pb,  &QPushButton::released,
                    w_ptr, &QWidget::show);
            break;
        }
}

connect_by_name.h

#ifndef CONNECT_BY_NAME_H
#define CONNECT_BY_NAME_H

#include <QWidget>
#include <QPushButton>
#include <QLayout>

class connect_by_name : public QWidget
{
    Q_OBJECT

public:
    explicit connect_by_name(QWidget *parent = nullptr);

private:
    void connect_to_unique_widget();

private:
    QHBoxLayout * m_hl {new QHBoxLayout{this}};
    QPushButton * m_pb {new QPushButton{"unique button"}};
};

#endif // CONNECT_BY_NAME_H

connect.pro

QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET   = connect
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        main.cpp \
        widget.cpp \
        connect_by_name.cpp

HEADERS += \
        widget.h \
        connect_by_name.h
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!