2011-09-04 11 views
6

Ho un telaio tkinter e un pulsante collegato ad esso:Tkinter vincolante una funzione con argomenti per un widget

from tkinter import * 

def rand_func(a,b,c,effects): 
    print (a+b+c) 

root=Tk() 
frame=Frame(root) 
frame.bind("<Return>",lambda a=10, b=20, c=30: rand_func(a,b,c)) 
frame.pack() 

button=Button(frame, text="click me", command=lambda a=1,b=2,c=3,eff=None:rand_func(a,b,c)) 
button.pack() 

root.mainloop() 

voglio la stessa funzione da eseguire quando l'utente preme entrare e quando preme il pulsante. Purtroppo, il codice sopra riportato dà un errore al collegamento del frame. Qualcuno conosce una soluzione a questo problema?

risposta

12

Quando si crea un legame con bind, Tkinter aggiunge automaticamente un argomento che ha informazioni sull'evento. Dovrai tenerne conto nella tua definizione rand_func o nel modo in cui la chiami.

Questo argomento è non incluso quando si utilizza l'attributo command. È necessario fare attenzione a considerare questo argomento in più sia nel modo in cui si chiama la funzione in ciascun caso, sia nel modo in cui la funzione interpreta i suoi parametri.

Ecco una soluzione che utilizza lambda nell'associazione per accettare l'evento extra solo quando si utilizza il comando bind, ma non lo si passa al comando finale.

import tkinter as tk 

class SampleApp(tk.Tk): 
    def __init__(self, *args, **kwargs): 
     tk.Tk.__init__(self, *args, **kwargs) 
     self.frame = tk.Frame(self) 
     self.frame.pack() 
     self.button = tk.Button(self.frame, text="click me", 
          command=lambda a=1, b=2, c=3: 
           self.rand_func(a, b, c)) 
     self.button.pack() 
     self.frame.bind("<Return>", 
         lambda event, a=10, b=20, c=30: 
          self.rand_func(a, b, c)) 
     # make sure the frame has focus so the binding will work 
     self.frame.focus_set() 

    def rand_func(self, a, b, c): 
     print "self:", self, "a:", a, "b:", b, "c:", c 
     print (a+b+c) 

app = SampleApp() 
app.mainloop() 

Detto questo, è raro che il collegamento a un telaio sia la cosa giusta da fare. In genere, una cornice non avrà la messa a fuoco della tastiera e, a meno che non sia messa a fuoco, la rilegatura non si attiverà mai. Se si imposta un binding globale, è necessario eseguire il binding al tag di binding "all" (utilizzando il metodo bind_all) o al widget di livello superiore.

+0

Grazie mille, come hai suggerito bind_all era quello di cui avevo bisogno; –

+0

È importante notare che _automaticamente aggiunge un argomento che contiene informazioni sull'evento_ si applica solo ai callback associati al metodo 'bind'. Quelli legati con l'opzione 'comando' (in costruttore o con' configure() ') non ricevono tale oggetto evento. Questa distinzione non è facile da individuare nei documenti (almeno non ne ho trovato nessuno), ma ecco [conferma] (https://stackoverflow.com/questions/36726716/what-is-the-difference-traving- command-and-bind-in-tkinter) –

+1

@ o'rety: Ho aggiornato la risposta per rispondere alle tue preoccupazioni. –

1

ne dite:

from Tkinter import * 

def rand_func(eff=None,a=1,b=2,c=3): 
    print (a+b+c) 

root=Tk() 
root.bind("<Return>",lambda eff:rand_func(eff,a=10,b=20,c=30)) 

frame=Frame(root) 
frame.pack() 

button=Button(frame, text="click me", command=lambda:rand_func(None,1,2,3)) 
button.pack() 

root.mainloop() 
+0

Hai dimenticato di scrivere nel codice che gli argomenti sono diversi, modifica la domanda –

Problemi correlati