2012-02-04 28 views
5

¿Existe alguna manera trivial o elegante de diferenciar entre muchas fuentes de señal del mismo tipo en PySide/PyQt?Diferenciar entre las fuentes de señal en PySide

Estoy aprendiendo PySide. He escrito una aplicación simple, que multiplica dos números de dos objetos QLineEdit() diferentes. El resultado se muestra en el tercer QLineEdit.

Multiplicador y multiplicando QLineEdit.textChanged() las señales están conectadas a un método (TxtChanged). En este método, tengo que diferenciar entre las fuentes de señal. Después de algunos ensayos me di cuenta de alguna solución basada en el texto de marcador de posición (4 líneas por debajo de "¿hay otra manera?" Comentario en mi código)

código:

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() 

mejores deseos, ostrzysz

+0

Gracias a todos por las respuestas. ¡Atentamente! – ostrzysz

Respuesta

3

Una cosa que me molesta más en su código es que está usando placeholderText para diferenciar. QObject s tiene otra propiedad llamada objectName que es más adecuada para su tarea. Y no necesita usar sender.text() para obtener el texto de QLineEdit. textChanged ya lo envía, por lo que lo tendrá en su parámetro text.

Además, usar un diccionario en lugar de dos variables separadas (multiplier y multiplicand) simplificará aún más su código.

Aquí está el código cambiado:

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)) 
+0

Buen punto sobre 'setObjectName', pero personalmente prefiero' functools.enfoque parcial' como en la respuesta @jsbueno, porque es explícito. Y 'QObject.sender()' tiene muchos inconvenientes, p. en el entorno mutlithreaded. – reclosedev

+0

Muchas gracias, ¡eso es exactamente lo que estaba buscando! Atentamente. – ostrzysz

6

Puede usar la función functools.partial y, por lo tanto, conectar sus señales directamente a su método/función, pero a un objeto python que automáticamente invocará su función con algunos datos adicionales que usted pase:

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" 
     ... 

parciales es parte de la stdlib, y es muy fácil de leer, pero siempre se puede utilizar lambda en lugar de parcial para el mismo efecto -

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

De esta manera el objeto dado por la expresión lambda será un temporal función que usará los valores para "self" y "a1_edit" de las variables locales actuales (en el momento en que se hace clic en el botón), y la devolución de llamada de Pyside proporcionará la variable llamada "text".

2

Aunque @jsbueno y @Avaris respondido a su pregunta directa acerca de las fuentes de señal, no me retransmitir en esta fuentes en su caso concreto. Puede hacer que los miembros de instancia a1_edit y a2_edit:

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

Se simplificarán su función 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)) 

Además, en lugar de manejar ValueError excepción, puede utilizar QIntValidator para los controles de entrada:

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