Reputation: 14651
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 (e.g.: mouseRelease
),
I need widget A
to call a function and to do some computing, processing data.
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.
Both these widgets are custom widgets derived from 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.
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.
Upvotes: 4
Views: 14411
Reputation: 9078
Update answer of @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_())
Upvotes: 9
Reputation:
Here is a example demonstrating signals/slots connections between two widgets in 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_())
Upvotes: 12
Reputation: 1707
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
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
#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 <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
#include "classa.h"
classA::classA(QObject *parent) :
QObject(parent)
{
}
void classA::emitsig()
{
emit signal();
}
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
#include "classb.h"
classB::classB(QObject *parent) :
QObject(parent)
{
}
void classB::on_signal()
{
QMessageBox *msgBox = new QMessageBox();
msgBox->setText("signal emitted!");
msgBox->exec();
}
Upvotes: 1
Reputation: 101959
I think you can use two different approaches here: make the A
and B
classes tightly coupled, or using the main-window as mediator.
In the first case you will have to "let A
know B
", meaning that A
has a reference to B
. In this case you don't even have to do signals & slots at all but you can simply call B
's methods directly.
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.
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.
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
.
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)
Upvotes: 3