PyQt the correct use of emit () and pyqtSignal ()

I am reading some PyQt5 documentation to come up with a simple signal slot mechanism. I stopped due to design considerations.

Consider the following code:

import sys from PyQt5.QtCore import (Qt, pyqtSignal) from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, QVBoxLayout, QApplication) class Example(QWidget): def __init__(self): super().__init__() self.initUI() def printLabel(self, str): print(str) def logLabel(self, str): '''log to a file''' pass def initUI(self): lcd = QLCDNumber(self) sld = QSlider(Qt.Horizontal, self) vbox = QVBoxLayout() vbox.addWidget(lcd) vbox.addWidget(sld) self.setLayout(vbox) #redundant connections sld.valueChanged.connect(lcd.display) sld.valueChanged.connect(self.printLabel) sld.valueChanged.connect(self.logLabel) self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Signal & slot') self.show() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) 

To track changes made to the slider, I simply print and log the changes made. What I don't like about the code is that I have to call the sld.valueChanged slot three times to send the same information to 3 different slots.

Is it possible to create your own pyqtSignal that sends an integer to a single slot function. And, in turn, does the slot function emit the changes that need to be done?

  • Perhaps I do not quite understand the purpose of emit() , because there are no good examples of its use in PyQt Signal-Slot docs . All that we have been given is an example of how to implement emit without parameters.

I would like to create a function that processes the emit function. Consider the following:

 import sys from PyQt5.QtCore import (Qt, pyqtSignal) from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, QVBoxLayout, QApplication) class Example(QWidget): def __init__(self): super().__init__() #create signal self.val_Changed = pyqtSignal(int, name='valChanged') self.initUI() def initUI(self): lcd = QLCDNumber(self) sld = QSlider(Qt.Horizontal, self) vbox = QVBoxLayout() vbox.addWidget(lcd) vbox.addWidget(sld) self.setLayout(vbox) sld.val_Changed.connect(self.handle_LCD) self.val_Changed.emit() self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Signal & slot') self.show() def handle_LCD(self, text): '''log''' print(text) '''connect val_Changed to lcd.display''' if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) 

There are obviously some serious design flaws here. I can’t wrap my head in the order of function calls. And I do not implement pyqtSignal correctly. However, I believe that correctly formulating the following 3 points will help me create a suitable application:

  • For a predefined signal: send a signal to the slot function. The slot can be redefined to use signal values.
  • Generate a pyqtSignal object with some parameters. It is not yet clear what the purpose of these parameters is and how they differ from the “emit” parameters.
  • emit can be overridden to send specific signal values ​​to the slot function. It is not yet clear why I will need to send different values ​​from previously existing signal methods.

Feel free to completely change the code for what I'm trying to do, because I still haven't figured out how much it is in the realm of good style.

+8
source share
1 answer

You can define your own slot (any python called) and connect it to the signal, and then call other slots from this slot.

 class Example(QWidget): def __init__(self): super().__init__() self.initUI() def printLabel(self, str): print(str) def logLabel(self, str): '''log to a file''' pass @QtCore.pyqtSlot(int) def on_sld_valueChanged(self, value): self.lcd.display(value) self.printLabel(value) self.logLabel(value) def initUI(self): self.lcd = QLCDNumber(self) self.sld = QSlider(Qt.Horizontal, self) vbox = QVBoxLayout() vbox.addWidget(self.lcd) vbox.addWidget(self.sld) self.setLayout(vbox) self.sld.valueChanged.connect(self.on_sld_valueChanged) self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Signal & slot') 

In addition, if you want to define your own signals, they must be defined as class variables.

 class Example(QWidget): my_signal = pyqtSignal(int) 

The pyqtSignal arguments determine the types of objects that will be emit on this signal, so in this case you could do

 self.my_signal.emit(1) 

emit can be overridden to send specific signal values ​​to a slot function. It is not yet clear why I will need to send different values ​​from previously existing signal methods.

Normally you should not emit embedded signals. You only need to generate the signals that you define. When defining a signal, you can define different signatures with different types, and the slots can choose which signature they want to connect to. For example, you can do this

 my_signal = pyqtSignal([int], [str]) 

This will determine the signal with two different signatures, and the slot can connect to one of

 @pyqtSlot(int) def on_my_signal_int(self, value): assert isinstance(value, int) @pyqtSlot(str) def on_my_signal_str(self, value): assert isinstance(value, str) 

In practice, I rarely overload signal signatures. Normally, I would simply create two separate signals with different signatures, and not overload the same signal. But it exists and is supported in PyQt because Qt has signals that are overloaded in this way (e.g. QComboBox.currentIndexChanged )

+11
source

Source: https://habr.com/ru/post/1246590/


All Articles