2012-02-04 6 views
5

C'è modo banale o elegante differenziare tra numerose sorgenti di segnale dello stesso tipo in PySide/PyQt?Differenziazione tra le sorgenti di segnale in PySide

Sto imparando PySide. Ho scritto una semplice applicazione, che moltiplica due numeri da due diversi oggetti QLineEdit(). Il risultato viene visualizzato nel terzo QLineEdit.

moltiplicatore e moltiplicando QLineEdit.textChanged() segnali sono collegati a un metodo (TxtChanged). In questo metodo devo distinguere tra sorgenti di segnale. Dopo alcune prove ho capito un po 'di soluzione basata su testo segnaposto (4 righe sotto "c'è un altro modo?" Commento nel mio codice)

codice:

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

migliori saluti, ostrzysz

+0

Grazie a tutti per le risposte. I migliori saluti! – ostrzysz

risposta

3

Una cosa che mi bug più nel codice è che si sta utilizzando placeholderText per differenziare. QObject s ha un'altra proprietà chiamata objectName che è più adatta alla tua attività. Inoltre, non è necessario utilizzare sender.text() per ottenere il testo di QLineEdit. textChanged lo invia già, quindi lo avrai nel tuo parametro text.

Inoltre, l'utilizzo di un dizionario anziché di due variabili separate (multiplier e multiplicand) semplificherà ulteriormente il codice.

Ecco il codice modificato:

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

Buon punto su 'setObjectName', ma personalmente preferisco' functools.approccio parziale come nella risposta @jsbueno, perché è esplicito. E 'QObject.sender()' ha molti svantaggi, ad es. in ambiente mutlithreaded. – reclosedev

+0

Grazie mille, è esattamente quello che stavo cercando! I migliori saluti. – ostrzysz

6

Puoi usare la funzione functools.partial - e quindi connettere i tuoi segnali direttamente al tuo metodo/funzione ma piuttosto a un oggetto python che chiamerà automaticamente la tua funzione con alcuni dati extra che passi:

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

partial fa parte della stdlib, ed è molto leggibile, ma si può sempre utilizzare lambda anziché parziale per lo stesso effetto -

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

In questo modo l'oggetto risultante dalla espressione lambda sarà una temporanea funzione che utilizzerà i valori per "self" e "a1_edit" dalle variabili locali correnti (al momento in cui si fa clic sul pulsante) e la variabile denominata "testo" verrà fornita dal callback di Pyside.

2

Anche se @jsbueno e @Avaris risposto alla tua domanda diretta sulla sorgenti di segnale, non vorrei trasmettere su questo fonti nel caso concreto. È possibile effettuare i membri di istanza a1_edit e a2_edit:

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

Sarà semplificare il TxtChanged funzione:

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

Inoltre, invece di gestire ValueError eccezione, è possibile utilizzare QIntValidator per i controlli di input:

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