PyQt 正确使用emit() 和pyqtSignal() [英] PyQt proper use of emit() and pyqtSignal()

查看:285
本文介绍了PyQt 正确使用emit() 和pyqtSignal()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读有关 PyQt5 的一些文档,以提出一个简单的信号槽机制.由于设计考虑,我已停止.

考虑以下代码:

导入系统从 PyQt5.QtCore 导入(Qt,pyqtSignal)从 PyQt5.QtWidgets 导入(QWidget、QLCDNumber、QSlider、QVBoxLayout、QApplication)类示例(QWidget):def __init__(self):super().__init__()self.initUI()def printLabel(self, str):打印(字符串)def logLabel(self, str):'''登录到文件'''经过定义 initUI(self):lcd = QLCDNumber(self)sld = QSlider(Qt.Horizo​​ntal, self)vbox = QVBoxLayout()vbox.addWidget(lcd)vbox.addWidget(sld)self.setLayout(vbox)#冗余连接sld.valueChanged.connect(lcd.display)sld.valueChanged.connect(self.printLabel)sld.valueChanged.connect(self.logLabel)self.setGeometry(300, 300, 250, 150)self.setWindowTitle('信号和槽')自我展示()如果 __name__ == '__main__':app = QApplication(sys.argv)ex = 示例()sys.exit(app.exec_())

要跟踪对滑块所做的更改,我只需打印并记录所做的更改.我不喜欢这段代码的是,我需要三次调用 sld.valueChanged 槽来将相同的信息发送到 3 个不同的槽.

是否可以创建我自己的 pyqtSignal 将整数发送到单个插槽函数.反过来让槽函数发出需要进行的更改?

  • 也许我不完全理解 emit() 的目的,因为 PyQt 信号槽文档.我们所提供的只是一个示例,说明如何实现不带参数的 emit.

我想做的是创建一个处理发射函数的函数.考虑以下几点:

导入系统从 PyQt5.QtCore 导入(Qt,pyqtSignal)从 PyQt5.QtWidgets 导入(QWidget、QLCDNumber、QSlider、QVBoxLayout、QApplication)类示例(QWidget):def __init__(self):super().__init__()#创建信号self.val_Changed = pyqtSignal(int, name='valChanged')self.initUI()定义 initUI(self):lcd = QLCDNumber(self)sld = QSlider(Qt.Horizo​​ntal, 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('信号和槽')自我展示()def handle_LCD(self, text):'''日志'''打印(文本)'''将 val_Changed 连接到 lcd.display'''如果 __name__ == '__main__':app = QApplication(sys.argv)ex = 示例()sys.exit(app.exec_())

这里显然存在一些严重的设计缺陷.我无法理解函数调用的顺序.而且我没有正确实现 pyqtSignal.但是,我确实相信正确说明以下 3 点将有助于我制作出合适的应用程序:

  1. 对于预定义的信号:将信号发送到槽函数.可以重新实现槽以使用信号值.
  2. 生成带有一些参数的 pyqtSignal 对象.目前尚不清楚这些参数的用途以及它们与emit"参数的区别.
  3. emit 可以重新实现以将特定信号值发送到槽函数.目前还不清楚为什么我需要从以前存在的信号方法发送不同的值.

随意完全改变我正在尝试做的代码,因为我还没有弄清楚它是否在良好的风格领域.

解决方案

您可以定义自己的插槽(任何 Python 可调用的插槽)并将其连接到信号,然后从该插槽调用其他插槽.

类示例(QWidget):def __init__(self):super().__init__()self.initUI()def printLabel(self, str):打印(字符串)def logLabel(self, str):'''登录到文件'''经过@QtCore.pyqtSlot(int)def on_sld_valueChanged(self, value):self.lcd.display(值)self.printLabel(值)self.logLabel(value)定义 initUI(self):self.lcd = QLCDNumber(self)self.sld = QSlider(Qt.Horizo​​ntal, 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('信号和槽')

另外,如果你想定义你自己的信号,它们必须被定义为类变量

类示例(QWidget):my_signal = pyqtSignal(int)

pyqtSignal 的参数定义将在该信号上发射的对象类型,因此在这种情况下,您可以这样做

self.my_signal.emit(1)

<块引用>

emit 可以重新实现以将特定的信号值发送到插槽功能.目前还不清楚为什么我需要发送不同的来自先前存在的信号方法的值.

您通常不应该发出内置信号.您应该只需要发出您定义的信号.在定义信号时,可以定义不同类型的不同签名,槽可以选择自己想要连接的签名.例如,你可以这样做

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

这将定义一个具有两个不同签名的信号,一个插槽可以连接到任何一个

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

在实践中,我很少重载信号签名.我通常只会创建两个具有不同签名的独立信号,而不是重载相同的信号.但它存在并在 PyQt 中受支持,因为 Qt 具有以这种方式重载的信号(例如.QComboBox.currentIndexChanged)

I am reading through some documentation on PyQt5 to come up with a simple signal-slot mechanism. I have come to a halt due to a design consideration.

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 the changes made to the slider, I simply print and log the changes made. What I do not like about the code is that I am required to call the sld.valueChanged slot thrice to send the same information to 3 different slots.

Is it possible to create my own pyqtSignal that sends an integer to a single slot function. And in turn have the slot function emit the changes that need to be made?

  • Maybe I don't fully understand the purpose of emit() because there are no good examples of it's purpose in the PyQt Signal-Slot docs. All we're given is an example of how to implement an emit with no parameters.

What I would like to do is create a function that handles 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 cannot wrap my head around the order of function calls. And I am not implementing pyqtSignal correctly. I do however believe that correctly stating the following 3 points will help me produce a proper app:

  1. For a predefined signal: send the signal to the slot function. Slot can be reimplemented to use the signal values.
  2. Produce pyqtSignal object with some parameters. It is not yet clear what the purpose of these parameters are and how they differ from 'emit' parameters.
  3. emit can be reimplemented to send specific signal values to the slot function. It is also not yet clear why I would need to send different values from previously existing signal methods.

Feel free to completely alter the code for what I am trying to do because I have not yet figured out if its in the realm of good style.

解决方案

You can define your own slot (any python callable) and connect that to the signal, then call the other slots from that one 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')

Also, if you want to define your own signals, they have to be defined as class variables

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

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

self.my_signal.emit(1)

emit can be reimplemented to send specific signal values to the slot function. It is also not yet clear why I would need to send different values from previously existing signal methods.

You generally shouldn't be emitting the built in signals. You should only need to emit signals that you define. When defining a signal, you can define different signatures with different types, and slots can choose which signature they want to connect to. For instance, you could do this

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

This will define a signal with two different signatures, and a slot could connect to either one

@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. I would normally just create two separate signals with different signatures rather than overloading the same signal. But it exists and is supported in PyQt because Qt has signals that are overloaded this way (eg. QComboBox.currentIndexChanged)

这篇关于PyQt 正确使用emit() 和pyqtSignal()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆