假设我们有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本身使用自己的插槽连接到它。
由于
答案 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