区分PySide中的信号源



在PySide/PyQt中,有没有简单或优雅的方法来区分许多相同类型的信号源?

我正在学习PySide。我已经编写了一个简单的应用程序,它将来自两个不同QLineEdit()对象的两个数字相乘。结果显示在第三个QLineEdit中。

乘法器和被乘数QLineEdit.textChanged()信号连接到一个方法(TxtChanged)。在这种方法中,我必须区分信号源。经过一些试验,我找到了一些基于占位符文本的解决方法(代码中"还有其他方法吗?"注释下方4行)

代码:

import sys
from PySide import QtGui, QtCore
class myGUI(QtGui.QWidget):
    def __init__(self, *args, **kwargs):
        QtGui.QWidget.__init__(self, *args, **kwargs)
        self.multiplier = 0
        self.multiplicand = 0
        self.myGUIInit()
    def myGUIInit(self):
        # input forms
        a1_label = QtGui.QLabel("a1")
        a1_edit = QtGui.QLineEdit()
        a1_edit.setPlaceholderText("a1")
        a2_label = QtGui.QLabel("a2")
        a2_edit = QtGui.QLineEdit()
        a2_edit.setPlaceholderText("a2")
        # output form
        a1a2_label = QtGui.QLabel("a1*a2")
        self.a1a2_edit = QtGui.QLineEdit()
        self.a1a2_edit.setReadOnly(True)

        # forms events
        a1_edit.textChanged.connect(self.TxtChanged)
        a2_edit.textChanged.connect(self.TxtChanged)
        # grid
        grid = QtGui.QGridLayout()
        grid.setSpacing(10)
        grid.addWidget(a1_label,1,0)
        grid.addWidget(a1_edit,1,1)
        grid.addWidget(a2_label,2,0)
        grid.addWidget(a2_edit,2,1)
        grid.addWidget(a1a2_label,3,0)
        grid.addWidget(self.a1a2_edit,3,1)
        self.setLayout(grid)
        self.setGeometry(100,100,200,200)
        self.setWindowTitle("a*b")
        self.show()
    def TxtChanged(self,text):
        sender = self.sender()
        sender_text = sender.text()
        if sender_text == '': sender_text = '0'
        # is there another way?
        if sender.placeholderText() == 'a1':
            self.multiplicand = sender_text
        else:
            self.multiplier = sender_text
        product = int(self.multiplier) * int(self.multiplicand)
        print(self.multiplier,self.multiplicand,product)
        self.a1a2_edit.setText(str(product))

def main():
    app = QtGui.QApplication(sys.argv)
    mainWindow = myGUI()
    sys.exit(app.exec_())
main()

致以最良好的问候,ostrzysz

您可以使用functools.partial函数,因此可以将信号直接连接到您的方法/函数,而是连接到一个python对象,该对象将自动调用您的函数,并传递一些额外的数据:

from functools import partial
...
        ....
        a1_edit.textChanged.connect(partial(self.TxtChanged, a1_edit))
        a2_edit.textChanged.connect(partial(self.TxtChanged, a2_edit))
        ...
    def TxtChanged(self,sender, text):
        # and here you have the "sender" parameter as it was filled in the call to "partial"
        ...

partials是stdlib的一部分,可读性很强,但为了获得相同的效果,可以始终使用lambda而不是partial-

a1_edit.textChanged.connect(lambda text: self.TxtChanged(a1_edit, text))

通过这种方式,lambda表达式产生的对象将是一个临时函数,它将使用当前局部变量(单击按钮时)中的"self"one_answers"a1_edit"的值,并且名为"text"的变量将由Pyside的回调提供。

代码中最让我头疼的一件事是使用placeholderText进行区分。QObject的另一个属性objectName更适合您的任务。并且,您不需要使用sender.text()来获取QLineEdit的文本。textChanged已经发送了它,所以您将在text参数中包含它。

此外,使用字典而不是两个单独的变量(multipliermultiplicand)将进一步简化代码。

这是更改后的代码:

class myGUI(QtGui.QWidget):
    def __init__(self, *args, **kwargs):
        QtGui.QWidget.__init__(self, *args, **kwargs)
        self.data = {"multiplier": 0,
                     "multiplicand": 0}
        self.myGUIInit()
    def myGUIInit(self):
        a1_label = QtGui.QLabel("a1")
        a1_edit = QtGui.QLineEdit()
        a1_edit.setObjectName("multiplicand")
        a2_label = QtGui.QLabel("a2")
        a2_edit = QtGui.QLineEdit()
        a2_edit.setObjectName("multiplier")
        # skipped the rest because same
    def TxtChanged(self, text):
        sender = self.sender()
        # casting to int while assigning seems logical.
        self.data[sender.objectName()] = int(text)
        product = self.data["multiplier"] * self.data["multiplicand"]
        print(self.data["multiplier"], self.data["multiplicand"], product)
        self.a1a2_edit.setText(str(product))

虽然@jsbueno和@Avaris回答了您关于信号源的直接问题,但我不会在您的具体案例中介绍这些源。您可以使实例成员a1_edita2_edit:

...
self.a1_edit = QtGui.QLineEdit()
...
self.a2_edit = QtGui.QLineEdit()
...

它将简化您的TxtChanged功能:

def TxtChanged(self,text):
    try:
        multiplier = int(self.a1_edit.text())
        multiplicand = int(self.a2_edit.text())
    except ValueError:
        self.a1a2_edit.setText('Enter two numbers')
        return
    product = multiplier * multiplicand
    print(multiplier, multiplicand, product)
    self.a1a2_edit.setText(str(product))

此外,您可以将QIntValidator用于输入控件,而不是处理ValueError异常:

self.int_validator = QtGui.QIntValidator()
self.a1_edit.setValidator(self.int_validator)
self.a2_edit.setValidator(self.int_validator)

最新更新