多层UI小部件中的信号和插槽

时间:2010-08-03 17:10:14

标签: qt user-interface signals slot

假设我们有follogin用户界面:

+--------------------------+
|W1       +--------------+ |
|         |W2            | |
|         | +----------+ | |
|         | |W3        | | |
|         | +----------+ | |
|         |              | |
|         +--------------+ |
+--------------------------+

W3对W1中出现的某个信号(或以下级别,即qApp)感兴趣。

我们的想法是独立开发W3。但有人必须进行信号/插槽连接。

如果我们希望W3不知道任何其他小部件,那么将W1中发出的信号连接到W3中的插槽会有什么好的做法/推荐方式,我们也不希望W1知道W3?

解决方案1: 将W1中的信号与W2中的信号(信号到信号技术)连接,从而将W2中的信号连接到W3中的插槽。

解决方案2: 生成qApp信号并将其与W2中的插槽连接在W2中。

解决方案3: 生成qApp信号并让W3本身使用自己的插槽连接到它。

由于

3 个答案:

答案 0 :(得分:3)

通常封闭小部件将小部件封装在其中并提供更高级别的界面。例如,如果W3包含几个需要根据某些状态启用/禁用的小部件,W3将管理该状态,为其提供API并相应地启用/禁用小部件。所以通常不需要直接从W1到W3。

如果小部件彼此不了解(例如,b / c W1是可以嵌入任何东西的通用容器小部件),则组装UI的人知道所有涉及的小部件,应该进行连接。

我不知道“qApp信号”是什么意思,但这听起来太像中心对象连接到所有东西,当然这也不是好设计。

也许你有一个你想到的具体例子?

答案 1 :(得分:1)

我们在这里使用的方法是“shell”建立连接。

shell是一个知道所涉及的所有小部件的对象。在这种情况下,W1,W2和W3。通常是组装用户界面的代码。

如果shell不知道W3(例如,因为W3是一个实现细节),那么W3的“所有者”应该建立连接,依此类推。

答案 2 :(得分:0)

您可以将名称设置为小部件,然后在任何位置发现它们:

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

或在父窗口小部件中:

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