Enviando mensajes entre dos widgets usando señales y ranuras

Necesito tener widgets que se comuniquen entre ellos.

Mi Widget central tiene 2 instancias de widget: widget A (instancia de A() ), widget B (instancia de B() ) Cuando un widget A está sujeto a un evento (por ejemplo: mouseRelease ), necesito el widget A para llamar a una función Y para hacer algo de informática, procesando datos. Y luego necesito que estos datos procesados se pasen al widget B , que a su vez, al recibir estos datos del widget A , llamará a una función con estos datos, los procesará y hará algo más con ellos.

Ambos widgets son widgets personalizados derivados de QWidget . Estoy casi seguro de que necesito usar señales y ranuras, pero no entiendo cómo implementar partes de llamada de función.

He leído una y otra vez las explicaciones de Qt aquí: http://qt-project.org/wiki/Signals_and_Slots_in_PySide, sin embargo, no puedo averiguar cómo conectar dos widgets que procesan y envían datos.

Realmente agradecería alguna ayuda aquí. Si no puede responder en Python y aún es competente con C ++, explique, sin embargo, cómo usarlo en lugar de abstenerse.

    Aquí hay un ejemplo que muestra las conexiones de señales / ranuras entre dos widgets en 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_()) 

    Respuesta actualizada de @ user1006989 para 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_()) 

    Creo que puede usar dos enfoques diferentes aquí: haga que las clases A y B estén bien acopladas, o use la ventana principal como mediador.

    En el primer caso, tendrá que “avisar a A B “, lo que significa que A tiene una referencia a B En este caso, ni siquiera tiene que hacer señales y ranuras, solo puede llamar directamente a los métodos de B

    El otro enfoque es dejar que A emita una señal con un argumento que contiene los datos que B debe recibir, la ventana principal captura esta señal y llama a B con los datos. Alternativamente, puede colocar los datos en el atributo de una A y dejar que la ventana principal lo tome directamente desde aquí, sin pasarlo como argumento de la señal.

    El último método le permite escribir un poco más libremente A y B ya que A no tiene que saber cómo llamar a B

    Explicado en el código debería verse así:

     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) 

    Se puede hacer utilizando varios métodos, el más sencillo (no el más inteligente) es hacer una conexión intermedia, desde el objeto A hasta las ventanas principales, desde la ventana principal hasta la B

    mainwindow.h

     #ifndef MAINWINDOW_H #define MAINWINDOW_H #include  #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

     #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

     #ifndef CLASSA_H #define CLASSA_H #include  class classA : public QObject { Q_OBJECT public: explicit classA(QObject *parent = 0); signals: void signal(); public slots: void emitsig(); }; #endif // CLASSA_H 

    classa.cpp

     #include "classa.h" classA::classA(QObject *parent) : QObject(parent) { } void classA::emitsig() { emit signal(); } 

    classb.h

     #ifndef CLASSB_H #define CLASSB_H #include  #include  class classB : public QObject { Q_OBJECT public: explicit classB(QObject *parent = 0); signals: public slots: void on_signal(); }; #endif // CLASSB_H 

    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(); }