使用pythondi中存储的信号

2024-09-30 03:25:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我想动态地创建并操作许多小部件。我的想法是将小部件存储在dict(mywidgets)中,并用另一个dict(mysignals)中存储的信号触发它们。两个dict共享一个列表(名称)中定义的相同键,dict用for循环初始化。你知道吗

当我将信号连接到插槽时,我当前面临一个AttributeError:'PyQt5。QtCore.pyqt信号'对象没有属性'connect'。你知道吗

我尝试过禁用信号/插槽连接:GUI看起来不错,QLineEdit很好地存储在mywidgets中。mysignals项的类型正确:类“PyQt5”。QtCore.pyqt信号'. 你知道吗

你能解释一下这个问题是从哪里来的吗? 谢谢。你知道吗

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QPushButton, QVBoxLayout
from PyQt5.QtCore import pyqtSlot, pyqtSignal

class App(QWidget):

    names = ["foo","bar"]
    mysignals = {}    # Store several signals in a dict
    for name in names:
        mysignals[name] = pyqtSignal(str)

    def __init__(self):
        super().__init__()

        # Create Widgets
        self.btn_go = QPushButton("Go")     #Simple push button
        self.mywidgets = {}                   #Store several QLineEdit in a dict
        for name in self.names:
            self.mywidgets[name] = QLineEdit()

        # Connect signals
        self.btn_go.clicked.connect(self.on_click)                  #Connect push button
        for name in self.names:
            print(type(self.mysignals[name]))
            self.mysignals[name].connect(self.mywidgets[name].setText)  #Connect several signals

        # Configure layout
        layout = QVBoxLayout()
        layout.addWidget(self.btn_go)
        for name in self.names:
            layout.addWidget(self.mywidgets[name])
        self.setLayout(layout) 

        # Show widget
        self.show()


    @pyqtSlot()
    def on_click(self):
        data = {"foo":"Python3","bar":"PyQt5"}
        for key,value in data.items():
            self.mysignals[key].emit(value)

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

当按下按钮时,预期结果是在mywidgets[“foo”]和mywidgets[“bar”]QLineEdit小部件中分别显示Python3和PyQt5。你知道吗


Tags: nameinselffor信号names部件connect
2条回答

对不起,我想你把算法复杂化了,以便得到预期的结果。试试看:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QPushButton, QVBoxLayout
from PyQt5.QtCore    import pyqtSlot, pyqtSignal

class App(QWidget):
    def __init__(self, names):
        super().__init__()

        self.names = names
        layout = QVBoxLayout()

        # Create Widgets
        self.btn_go = QPushButton("Go")            # Simple push button
        self.btn_go.clicked.connect(self.on_click) # Connect push button
        layout.addWidget(self.btn_go)

        self.mywidgets = {}                        # Store several QLineEdit in a dict
        for name in self.names:
            self.mywidgets[name] = QLineEdit()    
            layout.addWidget(self.mywidgets[name])

        self.setLayout(layout) 

    @pyqtSlot()
    def on_click(self):
        data = {"foo":"Python3", "bar":"PyQt5"}
        for key, value in data.items():
            self.mywidgets[key].setText(value)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    names = ["foo", "bar"]
    ex = App(names)

    ex.show()
    sys.exit(app.exec_())

enter image description here

正如docs所指出的:

A signal (specifically an unbound signal) is a class attribute. When a signal is referenced as an attribute of an instance of the class then PyQt5 automatically binds the instance to the signal in order to create a bound signal. This is the same mechanism that Python itself uses to create bound methods from class functions.

信号声明为类的属性,但通过self引用时,会与对象绑定,即声明的信号与实例化的信号不同:

from PyQt5 import QtCore

class Foo(QtCore.QObject):
    fooSignal = QtCore.pyqtSignal()
    print("declared:", fooSignal)

    def __init__(self, parent=None):
        super(Foo, self).__init__(parent)
        print("instantiated:", self.fooSignal)

if __name__ == '__main__':
    import sys
    app = QtCore.QCoreApplication(sys.argv)
    obj = Foo()

输出:

declared: <unbound PYQT_SIGNAL )>
instantiated: <bound PYQT_SIGNAL fooSignal of Foo object at 0x7f4beb998288>

这就是产生错误的原因,因此,如果要使用信号,必须使用对象获取信号,以便我们可以检查属性并获取信号:

from PyQt5 import QtCore, QtGui, QtWidgets

class Widget(QtWidgets.QWidget):
    foo = QtCore.pyqtSignal(str)
    bar = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self.fill_signals()
        self.names = ["foo", "bar"]

        self.btn_go = QtWidgets.QPushButton("Go")
        self.mywidgets = {}
        for name in self.names:
            self.mywidgets[name] = QtWidgets.QLineEdit()
            signal = self.mysignals.get(name)
            if signal is not None:
                signal.connect(self.mywidgets[name].setText)

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.btn_go)
        for name in self.names:
            layout.addWidget(self.mywidgets[name])

        self.btn_go.clicked.connect(self.testing)

    def fill_signals(self):
        self.mysignals = dict()
        for p in dir(self):
            attr = getattr(self, p)
            if isinstance(attr, QtCore.pyqtBoundSignal):
                self.mysignals[p] = attr

    def testing(self):
        self.foo.emit("foo")
        self.bar.emit("bar")

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

相关问题 更多 >

    热门问题