我想动态创建然后操纵许多小部件。我的想法是将小部件存储在dict(mywidget)中,并用存储在另一个dict(mysignals)中的信号触发它们。两个字典共享在列表(名称)中定义的相同键,字典使用for循环初始化。
当我将信号连接到插槽时,我当前面临AttributeError:'PyQt5.QtCore.pyqtSignal'对象没有属性'connect'。
我试图禁用信号/插槽连接:GUI看起来不错,QLineEdit很好地存储在mywidgets中。 mysignals项目的类型正确:类'PyQt5.QtCore.pyqtSignal'。
能否请您解释一下问题的出处? 谢谢。
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。
答案 0 :(得分:0)
对不起,我认为您已经使算法复杂化以获得预期结果。试试吧:
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_())
答案 1 :(得分:0)
docs指出:
信号(特别是未绑定信号)是类属性。当一个 信号被引用为该类的实例的属性,然后 PyQt5自动将实例绑定到信号,以便 创建一个绑定信号。这与Python本身的机制相同 用于从类函数创建绑定方法。
一个信号被声明为该类的一个属性,但是当通过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_())