简体   繁体   English

使用信号和插槽在两个小部件之间发送消息

[英]Sending messages between two widgets using Signals and Slots

I need to have widgets communicating between each other. 我需要让小部件彼此之间进行通信。

My central Widget has 2 widget instances: widget A (instance of A() ), widget B (instance of B() ) When a widget A is subject to an event (eg: mouseRelease ), I need widget A to call a function and to do some computing, processing data. 我的中央窗口小部件具有2个插件实例: widget A (实例A() widget B (实例B()widget A经受一个事件(例如: mouseRelease ),我需要widget A调用一个函数并做一些计算,处理数据。 And then I need this processed data to be passed to the widget B , which in turn upon receiving this data from widget A , will call a function with this data, process it, and do something more with it. 然后我需要将这些已处理的数据传递给 widget B ,然后从widget A 接收此数据 ,将使用此数据调用函数,处理它,并使用它执行更多操作。

Both these widgets are custom widgets derived from QWidget . 这两个小部件都是从QWidget派生的自定义小部件。 I am almost certain I need to use signals and slots but I don't understand how to implement function call parts. 我几乎可以肯定我需要使用信号和插槽,但我不明白如何实现函数调用部分。

I've read over and over again explanations of Qt here: http://qt-project.org/wiki/Signals_and_Slots_in_PySide however I can not figure it out how to connect two widgets which both process data emitted and sent. 我在这里一遍又一遍地阅读Qt的解释: http//qt-project.org/wiki/Signals_and_Slots_in_PySide然而我无法弄清楚如何连接两个处理发送和发送数据的小部件。

I would really appreciate some help here. 我真的很感激这里的一些帮助。 If you can not answer in Python yet competent with C++, please explain nonetheless using it instead of refraining at all. 如果你不能用Python来回答C ++,那么请解释一下,然后使用它而不是克制。

Here is a example demonstrating signals/slots connections between two widgets in PyQt4: 下面是一个演示PyQt4中两个小部件之间的信号/插槽连接的示例:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from PyQt4 import QtCore, QtGui

class widgetB(QtGui.QWidget):
    procDone = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(widgetB, self).__init__(parent)

        self.lineEdit = QtGui.QLineEdit(self)
        self.button = QtGui.QPushButton("Send Message to A", self)
        self.layout = QtGui.QHBoxLayout(self)
        self.layout.addWidget(self.lineEdit)
        self.layout.addWidget(self.button)

        self.button.clicked.connect(self.on_button_clicked)

    @QtCore.pyqtSlot()
    def on_button_clicked(self):
        self.procDone.emit(self.lineEdit.text())

    @QtCore.pyqtSlot(str)
    def on_procStart(self, message):
        self.lineEdit.setText("From A: " + message)

        self.raise_()

class widgetA(QtGui.QWidget):
    procStart = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(widgetA, self).__init__(parent)

        self.lineEdit = QtGui.QLineEdit(self)
        self.lineEdit.setText("Hello!")

        self.button = QtGui.QPushButton("Send Message to B", self)
        self.button.clicked.connect(self.on_button_clicked)

        self.layout = QtGui.QHBoxLayout(self)
        self.layout.addWidget(self.lineEdit)
        self.layout.addWidget(self.button)

    @QtCore.pyqtSlot()
    def on_button_clicked(self):
        self.procStart.emit(self.lineEdit.text())

    @QtCore.pyqtSlot(str)
    def on_widgetB_procDone(self, message):
        self.lineEdit.setText("From B: " + message)

        self.raise_()


class mainwindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(mainwindow, self).__init__(parent)

        self.button = QtGui.QPushButton("Click Me", self)
        self.button.clicked.connect(self.on_button_clicked)

        self.setCentralWidget(self.button)

        self.widgetA = widgetA()
        self.widgetB = widgetB()

        self.widgetA.procStart.connect(self.widgetB.on_procStart)
        self.widgetB.procDone.connect(self.widgetA.on_widgetB_procDone)

    @QtCore.pyqtSlot()
    def on_button_clicked(self):
        self.widgetA.show()
        self.widgetB.show()

        self.widgetA.raise_()


if __name__ == "__main__":
    import sys

    app  = QtGui.QApplication(sys.argv)
    main = mainwindow()
    main.show()
    sys.exit(app.exec_())

Update answer of @user1006989 for PyQt5: 更新@ user1006989 for PyQt5的答案:

from PyQt5 import QtCore, QtGui, QtWidgets


class widgetB(QtWidgets.QWidget):

    procDone = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(widgetB, self).__init__(parent)

        self.lineEdit = QtWidgets.QLineEdit(self)
        self.button = QtWidgets.QPushButton("Send Message to A", self)
        self.layout = QtWidgets.QHBoxLayout(self)
        self.layout.addWidget(self.lineEdit)
        self.layout.addWidget(self.button)

        self.button.clicked.connect(self.on_button_clicked)

    @QtCore.pyqtSlot()
    def on_button_clicked(self):
        self.procDone.emit(self.lineEdit.text())

    @QtCore.pyqtSlot(str)
    def on_procStart(self, message):
        self.lineEdit.setText("From A: " + message)

        self.raise_()


class widgetA(QtWidgets.QWidget):
    procStart = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(widgetA, self).__init__(parent)

        self.lineEdit = QtWidgets.QLineEdit(self)
        self.lineEdit.setText("Hello!")

        self.button = QtWidgets.QPushButton("Send Message to B", self)
        self.button.clicked.connect(self.on_button_clicked)

        self.layout = QtWidgets.QHBoxLayout(self)
        self.layout.addWidget(self.lineEdit)
        self.layout.addWidget(self.button)

    @QtCore.pyqtSlot()
    def on_button_clicked(self):
        self.procStart.emit(self.lineEdit.text())

    @QtCore.pyqtSlot(str)
    def on_widgetB_procDone(self, message):
        self.lineEdit.setText("From B: " + message)

        self.raise_()


class mainwindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(mainwindow, self).__init__(parent)

        self.button = QtWidgets.QPushButton("Click Me", self)
        self.button.clicked.connect(self.on_button_clicked)

        self.setCentralWidget(self.button)

        self.widgetA = widgetA()
        self.widgetB = widgetB()

        self.widgetA.procStart.connect(self.widgetB.on_procStart)
        self.widgetB.procDone.connect(self.widgetA.on_widgetB_procDone)

    @QtCore.pyqtSlot()
    def on_button_clicked(self):
        self.widgetA.show()
        self.widgetB.show()

        self.widgetA.raise_()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    main = mainwindow()
    main.show()
    sys.exit(app.exec_())

I think you can use two different approaches here: make the A and B classes tightly coupled, or using the main-window as mediator. 我认为你可以在这里使用两种不同的方法:使AB类紧密耦合,或者使用主窗口作为中介。

In the first case you will have to "let A know B ", meaning that A has a reference to B . 在第一种情况下,你必须“让A知道B ”,这意味着A有一个对B的引用。 In this case you don't even have to do signals & slots at all but you can simply call B 's methods directly. 在这种情况下,你根本不需要做信号和插槽,但你可以直接调用B的方法。

The other approach is to let A emit a signal with an argument containing the data that should be received by B , the main-window catches this signal and calls B with the data. 另一种方法是让A发出一个带有参数的信号,该参数包含B应该接收的数据,主窗口捕获该信号并用数据调用B Alternatively you can put the data in an A 's attribute and let the main-window take it from here directly, without passing it as signal's argument. 或者,您可以将数据放在A的属性中,让主窗口直接从此处获取,而不将其作为信号的参数传递。

The latter method allows you to write a bit more freely A and B since A does not have to know how to call B . 后一种方法允许你更自由地写AB因为A不必知道如何调用B

Explained in code it should looks like this: 在代码中解释它应该如下所示:

class A(QWidget):
    the_signal = Signal(...)
    def mouseReleaseEvent(self, event):
        self.a_function()
        self.the_data = self.produce_data()
        self.the_signal.emit()

class B(QWidget):
    def process_data(self, data):
        pass

class MainWindow(QMainWindow):
    def __init__(self):
        self.a_widget = A()
        self.b_widget = B()
        self.a_widget.the_signal.connect(self.do_process)
        # if the signal has the data as argument:
        # self.a_widget.the_signal.connect(self.b_widget.process_data)
    def do_process(self):
        self.b_widget.process_data(self.a_widget.the_data)

It could be done using several methods , the easiest one (not the most clever) is making intermediate connection, from object A to mainwindows,mainwindow to B 它可以使用几种方法完成,最简单的方法(不是最聪明的)是进行中间连接,从对象A到主窗口,主窗口到B

mainwindow.h mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "classa.h"
#include "classb.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    classA *a;
    classB *b;

signals:
    void TosignalA();
    void TosignalB();

public slots:
    void emitB();

private slots:
    void on_pushButton_clicked();
};

#endif // MAINWINDOW_H

mainwindow.cpp mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    a = new classA(this);
    b=new classB(this);
    connect(this,SIGNAL(TosignalA()),this->a,SLOT(emitsig()));
    connect(this->a,SIGNAL(signal()),this,SLOT(emitB()));
    connect(this,SIGNAL(TosignalB()),this->b,SLOT(on_signal()));

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::emitB()
{
    emit TosignalB();
}

void MainWindow::on_pushButton_clicked()
{
    emit TosignalA();
}

classa.h classa.h

#ifndef CLASSA_H
#define CLASSA_H

#include <QObject>

class classA : public QObject
{
    Q_OBJECT
public:
    explicit classA(QObject *parent = 0);

signals:
    void signal();

public slots:
    void emitsig();

};

#endif // CLASSA_H

classa.cpp classa.cpp

#include "classa.h"

classA::classA(QObject *parent) :
    QObject(parent)
{

}

void classA::emitsig()
{
    emit signal();
}

classb.h classb.h

#ifndef CLASSB_H
#define CLASSB_H

#include <QObject>
#include <QtGui>

class classB : public QObject
{
    Q_OBJECT
public:
    explicit classB(QObject *parent = 0);

signals:

public slots:
    void on_signal();

};

#endif // CLASSB_H

classb.cpp classb.cpp

#include "classb.h"

classB::classB(QObject *parent) :
    QObject(parent)
{
}
void classB::on_signal()
{
    QMessageBox *msgBox = new QMessageBox();
     msgBox->setText("signal emitted!");
     msgBox->exec();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM