Различение источников сигнала в PySide - PullRequest
5 голосов
/ 05 февраля 2012

Существует ли тривиальный или изящный способ различения многих источников сигналов одного типа в 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

Ответы [ 3 ]

6 голосов
/ 05 февраля 2012

Вы можете использовать функцию 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 и очень удобочитаем, но всегда можно использовать лямбду вместо частичного для того же эффекта -

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

Таким образом, объект, полученный с помощью лямбда-выражения, будет временной функцией, которая будет использовать значения «self» и «a1_edit» из текущих локальных переменных (в момент нажатия кнопки) и переменную с именем «текст» будет предоставлен обратным вызовом Pyside.

3 голосов
/ 05 февраля 2012

В вашем коде меня больше всего беспокоит то, что вы используете placeholderText для дифференциации. У QObject s есть еще одно свойство под названием objectName, которое больше подходит для вашей задачи. И вам не нужно использовать sender.text(), чтобы получить текст QLineEdit. textChanged уже отправляет его, так что вы получите его в параметре text.

Кроме того, использование словаря вместо двух отдельных переменных (multiplier и multiplicand) еще больше упростит ваш код.

Вот измененный код:

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))
2 голосов
/ 05 февраля 2012

Хотя @ jsbueno и @ Avaris ответили на ваш прямой вопрос об источниках сигнала, я бы не стал передавать эти источники в вашем конкретном случае. Вы можете сделать элементы экземпляра a1_edit и a2_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))

Кроме того, вместо обработки ValueError исключения можно использовать QIntValidator для элементов управления вводом:

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