Python tkinter deshabilita el botón hasta que se llenan todos los campos

Digamos que tengo 2 widgets de entrada, 1 menú de opciones (lista desplegable) y 1 botón en tkinter. ¿Cómo puedo configurar el estado del widget del botón en DESACTIVADO hasta que el usuario complete los 3 widgets? Esto es lo que tengo actualmente:

import Tkinter as tk root = tk.Tk() entry1=tk.Entry(root,width=15).grid(row=1,column=1) entry2=tk.Entry(root,width=15).grid(row=1,column=2) choices=('a','b','c') var=tk.StringVar(root) option=tk.OptionMenu(root,var,*choices) option.grid(row=1,column=3) button=tk.Button(root,text="submit") button.grid(row=1,column=4) root.mainloop() 

–EDITAR–

Lo intenté de esta manera, pero no creo que esta sea la forma correcta de hacerlo.

 import Tkinter as tk root = tk.Tk() def myfunction(event): x=var.get() y=entry1.get() z=entry2.get() print len(x),":",len(y),":",len(z) if len(y)>0 and len(x)>0 and len(z)>0: button.config(state='normal') else: button.config(state='disabled') entry1=tk.Entry(root,width=15) entry1.grid(row=1,column=1) entry2=tk.Entry(root,width=15) entry2.grid(row=1,column=2) choices=('a','b','c') var=tk.StringVar(root) option=tk.OptionMenu(root,var,*choices) option.grid(row=1,column=3) button=tk.Button(root,text="submit") button.grid(row=1,column=4) root.bind("", myfunction) root.mainloop() 

Las variables Tkinter tienen un método llamado trace para agregar un observador, por lo que se llama a la función de callback cuando cambia el valor. Creo que es mucho más eficiente que root.bind("", myfunction) :

 import Tkinter as tk root = tk.Tk() def myfunction(*args): x = var.get() y = stringvar1.get() z = stringvar2.get() if x and y and z: button.config(state='normal') else: button.config(state='disabled') stringvar1 = tk.StringVar(root) stringvar2 = tk.StringVar(root) var = tk.StringVar(root) stringvar1.trace("w", myfunction) stringvar2.trace("w", myfunction) var.trace("w", myfunction) entry1 = tk.Entry(root, width=15, textvariable=stringvar1) entry1.grid(row=1,column=1) entry2 = tk.Entry(root, width=15, textvariable=stringvar2) entry2.grid(row=1,column=2) choices = ('a','b','c') option = tk.OptionMenu(root, var, *choices) option.grid(row=1,column=3) button = tk.Button(root,text="submit") button.grid(row=1, column=4) root.mainloop() 

¿Qué hay de validate y validatecommand propiedades de la entrada?

 #!/usr/bin/env python3 import tkinter class App: def __init__(self): self.root = tkinter.Tk() self.variables = {} self.entries = {} self.vcmd = (self.root.register(self.observer), '%W', '%P') self.make_entry('fname') self.make_entry('sname') self.make_submit_button('Send') def make_entry(self, name): self.variables[name] = tkinter.StringVar() self.entries[name] = tkinter.Entry( self.root, textvariable=self.variables[name], validate='all', validatecommand=self.vcmd) self.entries[name].pack(side=tkinter.TOP) def make_submit_button(self, text): self.submit_button = tkinter.Button( self.root, text=text, state=tkinter.DISABLED) self.submit_button.pack(side=tkinter.BOTTOM) def observer(self, id_, value): id_ = int(id_[1:]) self.update_submit_button_state(entry_exclude=(value and id_ or None)) return True def update_submit_button_state(self, entry_exclude=None): if all( var.get() for name, var in self.variables.items() if id(self.entries[name]) != entry_exclude ): self.submit_button.config(state=tkinter.NORMAL) else: self.submit_button.config(state=tkinter.DISABLED) App().root.mainloop() 

Prueba esto:

 import Tkinter as tk root = tk.Tk() def myfunction(*event): x=var.get() y=entry1.get() z=entry2.get() print len(x),":",len(y),":",len(z) if len(y)>0 and len(x)>0 and len(z)>0: button.config(state='normal') else: button.config(state='disabled') entry1=tk.Entry(root,width=15) entry1.grid(row=1,column=1) entry2=tk.Entry(root,width=15) entry2.grid(row=1,column=2) choices=('a','b','c') var=tk.StringVar(root) option=tk.OptionMenu(root,var,*choices) option.grid(row=1,column=3) button=tk.Button(root,text="submit") button.grid(row=1,column=4) button.config(state='disabled') root.bind_class("Entry","",myfunction) var.trace('w', myfunction) root.mainloop()