为什么此信号/插槽代码不起作用

夸大

我有一个基本的信号/插槽代码,我想在一个小部件中发射一个信号,然后在另一个小部件中连接该信号。

#!/usr/bin/python3
# -*- coding: utf-8 -*-

from PyQt5.QtWidgets import QMainWindow, QAction, QApplication, QWidget, QPushButton, qApp, QLabel, QHBoxLayout, QVBoxLayout, QSplitter, QFileDialog
from PyQt5.QtGui import QIcon, QPixmap, QPainter, QImage
from PyQt5.QtCore import QSize, Qt, pyqtSignal, QObject
import sys, random
import qdarkstyle
from os import path

class SignalFactory(QObject):
    selectedTextureToLoad = pyqtSignal()

class Application(QMainWindow):
    def __init__(self):
        super().__init__()
        self.signals = SignalFactory()
        self.mainArea = MainArea()

        # Option 1 - Uncomment below / Works but strong coupling between widgets
        # self.signals.selectedTextureToLoad.connect(self.mainArea.doSomeStuff)

        self.setCentralWidget(self.mainArea)
        self.setGeometry(300, 300, 800, 400)
        self.show()

    def emitStuff(self):
        print("Emitting...")
        self.signals.selectedTextureToLoad.emit()

class MainArea(QWidget):
    def __init__(self):
        super().__init__()
        self.signals = SignalFactory()

        # Option 2 - Uncomment below / Does not work
        #self.signals.selectedTextureToLoad.connect(self.doSomeStuff)

    def doSomeStuff(self):
        print("Receiving...")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Application()
    ex.emitStuff()
    sys.exit(app.exec_())
  • 如果我取消注释选项1,则代码有效,并且接收到信号。但是,这两个小部件之间存在耦合。在这种情况下,这很好,因为一个小部件是另一个小部件的父级,并且自然会跟踪其子级。但是在更复杂的情况下,这意味着跟踪许多小部件只是为了配置信号,这并不好。

  • 如果我取消对选项2的注释,则该代码将不起作用,并且控制台仅显示“正在发射...”。这很烦人,因为在我看来,这是在一个位置配置信号并从另一位置发射信号而又不引入耦合的最干净的方法。

我在这里缺少基本的东西吗?

编辑:

如果您像这样修改代码,则通过添加returnASignal函数

from PyQt5.QtWidgets import QMainWindow, QAction, QApplication, QWidget, QPushButton, qApp, QLabel, QHBoxLayout, QVBoxLayout, QSplitter, QFileDialog
from PyQt5.QtGui import QIcon, QPixmap, QPainter, QImage
from PyQt5.QtCore import QSize, Qt, pyqtSignal, QObject
import sys, random
import qdarkstyle
from os import path

def returnASignal():
    print('Returning a signal')
    return pyqtSignal()

class SignalFactory(QObject):
    selectedTextureToLoad = returnASignal()

class Application(QMainWindow):
    def __init__(self):
        super().__init__()
        self.signals = SignalFactory()
        self.mainArea = MainArea()
        # Option 2 - Uncomment below / Works but strong coupling between widgets
        # self.signals.selectedTextureToLoad.connect(self.mainArea.doSomeStuff)
        self.setCentralWidget(self.mainArea)
        self.setGeometry(300, 300, 800, 400)
        self.show()

    def emitStuff(self):
        print("Emitting...")
        self.signals.selectedTextureToLoad.emit()

class MainArea(QWidget):
    def __init__(self):
        super().__init__()
        self.signals = SignalFactory()
        # Option 1 - Uncomment below / Does not work
        self.signals.selectedTextureToLoad.connect(self.doSomeStuff)

    def doSomeStuff(self):
        print("Receiving...")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Application()
    ex.emitStuff()
    sys.exit(app.exec_())

运行它时,控制台将显示以下内容:

Returning a signal
Emitting...

“返回信号”仅打印一次,而不打印两次,这表明尽管存在多个SignalFactory实例,但它们都共享同一selectedTextureToLoad对象。这绝对是适当的静态类成员,而不是实例变量。因此,信号对象到处都是相同的,我仍然不明白为什么选项2无法正常工作。

ekhumoro

这里没有真正的谜。信号对象的行为与类中定义的方法完全相同。

如果您放入一些调试打印,例如:

class SignalFactory(QObject):
    selectedTextureToLoad = returnASignal()
    print(selectedTextureToLoad)

    def foo(self): pass
    print(foo)

class Application(QMainWindow):
    def __init__(self):
        super().__init__()
        self.signals = SignalFactory()
        print(self.signals.selectedTextureToLoad)
        print(self.signals.foo)
        ...

class MainArea(QWidget):
    def __init__(self):
        super().__init__()
        self.signals = SignalFactory()
        print(self.signals.selectedTextureToLoad)
        print(self.signals.foo)

并运行您的示例,它将产生如下输出:

Returning a signal
<unbound PYQT_SIGNAL []>
<function SignalFactory.foo at 0x7f2a57b1c268>
<bound PYQT_SIGNAL selectedTextureToLoad of SignalFactory object at 0x7f2a57b96828>
<bound method SignalFactory.foo of <__main__.SignalFactory object at 0x7f2a57b96828>>
<bound PYQT_SIGNAL selectedTextureToLoad of SignalFactory object at 0x7f2a57b96948>
<bound method SignalFactory.foo of <__main__.SignalFactory object at 0x7f2a57b96948>>
Emitting...

如您所见,从实例访问时,信号和方法都是绑定对象,而从类访问时,它们都是未绑定对象。方法必须绑定到实例,以便self可以作为第一个参数传递。同样,信号对象必须绑定到实例,以确保连接的插槽仅接收来自发送它的特定实例的信号

因此,在您的示例中两个信号被命名selectedTextureToLoad-每个信号实例SignalFactory都会创建一个。您的示例不起作用,因为doSomeStuff插槽未连接到发出信号特定绑定信号对象selectedTextureToLoad

信号插槽机制设计用于对象之间的通信。没有已知的发送者就无法广播消息,因此必须始终在发送者和接收者之间建立显式连接。如果您想发送更通用的信号,请创建的全局实例SignalFactory

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章