сигналы и слоты в многослойных виджетах интерфейса - PullRequest
2 голосов
/ 03 августа 2010

Скажем, у нас есть UI follogin:

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

W3 интересуется определенным сигналом, излучаемым в W1 (или уровнем ниже, т.е. qApp).

Идея состоит в том, чтобыразрабатывать W3 самостоятельно.Но кто-то должен выполнить соединение сигнал / слот.

Какой будет хороший метод / рекомендуемый способ подключения сигнала, излучаемого в W1, в слот в W3, если мы хотим, чтобы W3 не знал ни о каком другом виджете, имы не хотим, чтобы W1 также знал о W3?

Решение 1: Подключите сигнал в W1 к сигналу в W2 (метод передачи сигнала в сигнал) и, следовательно, подключите сигнал в W2 к слоту в W3.

Решение 2. Сгенерируйте сигнал qApp и соедините его в W2 с разъемом в W3.

Решение 3. Сгенерируйте сигнал qApp и подключите к нему сам W3, используя свой собственный слот.

Спасибо

Ответы [ 3 ]

3 голосов
/ 04 августа 2010

Обычно включающий виджет инкапсулирует виджеты внутри него и обеспечивает интерфейс более высокого уровня. Например, если W3 содержит несколько виджетов, которые необходимо включить / отключить в зависимости от некоторого состояния, W3 будет управлять этим состоянием, предоставлять API для него и соответственно включать / отключать виджеты. Поэтому обычно нет необходимости переходить непосредственно от W1 к W3.

Если виджеты не знают друг о друге (например, b / c W1 - это общий контейнерный виджет, который может встраивать все что угодно), то тот, кто собирает пользовательский интерфейс, зная все задействованные виджеты, должен выполнить соединение.

Я не знаю, что вы подразумеваете под "сигналом qApp", но это слишком похоже на то, что центральный объект подключен ко всему, что, конечно, тоже не очень хороший дизайн.

Может быть, у вас есть конкретный пример, который вы имели в виду?

1 голос
/ 03 августа 2010

Подход, который мы здесь используем, заключается в том, что «оболочка» создает соединения.

Оболочка - это объект, который знает обо всех задействованных виджетах. В этом случае W1, W2 и W3. Обычно это код, который собирает пользовательский интерфейс.

Если оболочка не знает о W3 (потому что W3, например, является деталью реализации), то «владелец» W3 должен установить соединение и т. Д.

0 голосов
/ 07 февраля 2019

Вы можете установить имя для виджетов, а затем обнаружить их в любом месте:

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
...