pythonbuttondialogtkintersimpledialog

tkinter.simpledialog.Dialog leaves the initiating tkinter.Button depressed


I am using Python 3.3 on Windows 7. I have a tkinter application where one Button fires up a tkinter.simpledialog.Dialog. Like this (this is a complete, runnable example):

import tkinter
import tkinter.simpledialog

class Mainframe(tkinter.Frame):
    def __init__(self, parent):
        super(Mainframe, self).__init__(parent)
        self.parent = parent
        self.button = tkinter.Button(self, text="Open Dialog")
        open_dialog_op = lambda ev: self.open_dialog(ev)
        self.button.bind("<Button-1>", open_dialog_op)
        self.button.bind("<Return>", open_dialog_op)
        self.button.pack(side=tkinter.LEFT)

    def open_dialog(self, event):
        dialog = tkinter.simpledialog.Dialog(self.parent, "My Dialog")
        self.button.config(relief=tkinter.RAISED)  # does not help!

root = tkinter.Tk()
Mainframe(root).pack()
root.mainloop()

The behavior:

(Actually, my full application starts showing the button as depressed right after it's clicked, not only once the dialog closes again. I find this a lot more logical: The simpledialog local event loop grabs all events because the simpledialog is modal; this could include the <ButtonRelease-1> mouse event at the Button?)

Questions:

  1. Why does this happen?
  2. Why might the behavior in my full application differ?
  3. How can I avoid or repair both?

Solution

  • It's happening because you are partially overriding the default bindings which do the Right Thing.

    If you want a button to execute a function on a button activation the proper way to do this is to add a command option to the button. The reason I use "activation" instead of "press" is — as your code shows — there is more than one way to activate a button in tk: button-presses, return-presses, accelerator key presses, etc.

    The code you wrote does not replace the rather large set of default bindings. The answer by iCodez does correctly fix the most obvious defects, but letting the default bindings stand and using command= will work for the cases that you haven't tested (e.g. keyboard-only operation).