关于在哪里定义自定义信号和槽的连接的良好实践

问题描述 投票:0回答:1

当我在

script A
中发出信号并捕获它
script B
以在那里执行插槽时。
mysignalA.connect(myslotB)
应该去哪里? 在脚本 A 中为:
self.mysignalA.connect(B.myslotB)
或者在脚本 B 中为:
A.mysignalA.connnect(self.myslotB)

我的代码工作正常且可靠,但是:我有一个大项目,其中多个 Qthreads 分为多个文件,并且有点失去对所有信号/槽的跟踪。而且很多人都在研究它,所以这也没有帮助。

在这个具体示例中,我有一个线程处理 UDP 通信以将状态更新发送到外部系统,一个线程处理与 3D 打印机的串行通信,另一个线程处理一些温度建模。 现在

UDPsend
temperatureDtThread
都需要以不同的速率/时间读取 3D 打印机的温度,但我也无法使用相同的请求两次淹没串行通信,因此我决定触发
SLOT_request_temperature_reading
每当某个地方有人需要温度时,就会进行一些串行通信和翻译,然后通过
SIGNAL_temperature_reading
再次发出该温度读数,以便此时需要它的任何人都可以捕获。

UDPComms.py

class UDPsend(QThread):
    SIGNAL_temperature_req_UDP = pyqtSignal()
    
    def __init__(self, printer):
        self.SIGNAL_temperature_req_UDP.connect(printer.SLOT_request_temperature_reading)
        printer.SIGNAL_temperature_reading.connect(self.SLOT_get_temperature)

    def run(self):
        while True
            #DoSomethingSomething
            if required
                self.SIGNAL_temperature_req_UDP.emit()

    @pyqtslot(float)
    def SLOT_get_temperature(temperature_reading):
        self.temperature=temperature_reading #So i can use the temperature in this class now

打印机.py

class PrinterThread(QThred):
    SIGNAL_temperature_reading = pyqtSignal(float)

    def run(self):

        if self.Temp_reading_requested = True
            #DoSerialCommunicationAndStuff
            self.SIGNAL_temperature_reading.emit(self.mytemperature)

    @pyqtSlot()
    def SLOT_request_temperature_reading():
        self.Temp_reading_requested = True

tempDT.py

class temperatureDtThread(QThread):
    SIGNAL_temperature_req_DT = pyqtSignal()
    
    def __init__(self, printer)
    self.SIGNAL_temperature_req_DT.connect(printer.SLOT_request_temperature_reading)
    printer.SIGNAL_temperature_reading.connect(self.SLOT_temperature_read_out)

    def run(self):
        while True
            #DoSomethingSomething
            if required
                SIGNAL_temperature_req_DT.emit
        
    @pyqtSlot(float)
    def SLOT_temperature_read_out(temperature_reading):
        self.temperature=temperature_reading #So i can use the temperature in this class now

main.py

if __name__ == "__main__":
    printer_thread = printer.Printerthread()
    udp_thread = UDPComms.UDPSend(printer_thread)
    tempdt_thread = tempDT.temperatureDtThread(printer_thread)

    printer_thread.start()
    udp_thread.start()
    tempdt_thread.start()

example

所以现在在这种情况下,我尝试从

printer.py
外部进行连接,但背后没有太多推理。是否有一个常见的良好实践来定义信号和槽的连接?

python pyqt5 signals-slots
1个回答
0
投票

从理论上讲,对象通常应该是独立的,并且能够独立工作,无论它们放置在什么环境中。这显然并不总是可行,有时也是不可取的。

在 Qt 的情况下,QObject 通常应该只寻址其自身或其子对象,尽管该对象实际上是由其他对象使用的,或者甚至在除了该对象之外没有其他对象的情况下。

在对象的层次结构及其定义位置中,最好“从外部”创建这些连接,或者可以说,从理想的“控制器”创建这些连接,在您的情况下,这就是“主”中发生的情况。
创建从对象内部到外部对象的连接本身并没有错,因为通常情况下,建立连接的上下文是无关的。例外情况是信号和槽的线程上下文可能无法自动解析,但只要您使用正确的 QObject 及其方法/槽,这就不是问题。如果使用非 QObject、标准函数或 lambda,这显然可以改变。

在您的情况下,您在其他对象构造函数中提供的

printer_thread
实际上仅用于信号连接;虽然这样做是有意义的(并且理论上简化了“主”代码中的事情),但从更严格的意义上来说,它并不完全合适。更正确的解决方案不会在这些线程构造函数中使用打印机对象,而是从创建这些对象的位置创建连接:

# in main
printer_thread = printer.Printerthread()
udp_thread = UDPComms.UDPSend()
tempdt_thread = tempDT.temperatureDtThread()

printer_thread.Signal_temperature_reading.connect(
    udp_thread.SLOT_get_temperature)
printer_thread.SIGNAL_temperature_reading.connect(
    tempdt_thread.SLOT_temperature_read_out)
udp_thread.SIGNAL_temperature_req_UDP.connect(
    printer.SLOT_request_temperature_reading)
tempdt_thread.SIGNAL_temperature_req_DT.connect(
    printer.SLOT_request_temperature_reading)

这种方法的好处之一是所有连接都在同一个地方完成,使代码流更加一致。

如果许多相似的对象需要连接到相似的信号或槽,这也很有用。假设您有许多对象需要连接到打印机,并且它们都有一致的命名(这不是您的情况,我建议您这样做),那会更容易:

printer_thread = printer.Printerthread()
some_threads = [Whatever() for _ in range(10)]
for thread in some_threads:
    printer_thread.temperatureRead.connect(thread.temperatureReceived)
    thread.requestTemperature.connect(printer_thread.requestTemperature)

请注意,您的方法实际上没有任何问题:它有效,并且不会产生任何真正的问题。

像往常一样,好的或首选的做法大多是指导方针,而不是绝对的规则。因此,它们应该只在有意义的情况下应用,包括代码可读性/可移植性、对象结构清晰度以及层次结构之间没有直接关系的对象之间的相关性。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.