classification
Title: Tkinter, callback functions
Type: Stage: resolved
Components: Tkinter Versions: Python 3.1, Python 3.2, Python 3.3, Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Nikolay.Fomichev, gpolo, serhiy.storchaka, terry.reedy
Priority: normal Keywords:

Created on 2011-03-03 18:30 by Nikolay.Fomichev, last changed 2014-06-02 06:17 by terry.reedy. This issue is now closed.

Messages (5)
msg129990 - (view) Author: Nikolay Fomichev (Nikolay.Fomichev) Date: 2011-03-03 18:30
A simple code:

class App():  
    def __init__(self):
        self.root = tk.Tk()
        
        self.btn = tk.Button(self.root, text='Click me')
        self.btn.pack()
        self.btn.bind('<Button-1>', self.click)

        self.root.mainloop()
        
    def click(self, event):
        # Messagebox or filedialog
        pass


When the button is clicked, it calls the function where a filedialog or messagebox is called. After the function is done the button changes - it looks like it's pressed. Its relief is sunken. Something like "self.btn.config(relief=tk.RAISED)" has no effect - relief is raised, but the button still looks pressed.
If no dialogs are called, all is fine.

But... if instead of "bind" I use config option "command", it works - the function goes well with dialogs, etc and the button is really raised.

I checked this in 2.6.6, 2.7, 3.1.2 and 3.2 on Linux and Win, everywhere is the same tune.
msg130088 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2011-03-04 23:49
In 2.7 or 3.2, winxp, when I enclose your code with
from tkinter import tk #or Tkinter
...
App()

I get a window with a buttom that sinks and raises as I press and release the left button.

Please post complete runnable code that exhibits the problem.
Do not expect us to replace what you deleted.
msg130170 - (view) Author: Nikolay Fomichev (Nikolay.Fomichev) Date: 2011-03-06 13:50
Here it is... 


import sys
if sys.version_info[0] == 3:
    import tkinter as tk
    from tkinter import messagebox
    from tkinter import filedialog
else:
    import Tkinter as tk
    import tkMessageBox as messagebox
    import tkFileDialog as filedialog

class App():  
    def __init__(self):
        self.root = tk.Tk()
        
        self.btnMsg = tk.Button(self.root, text='Click me')
        self.btnMsg.pack()
        self.btnMsg.bind('<Button-1>', self.clickMsg)
        
        self.btnFd = tk.Button(self.root, text='Click me too')
        self.btnFd.pack()
        self.btnFd.bind('<Button-1>', self.clickFd)
        
        self.btnCommand = tk.Button(self.root, text='And now click me')
        self.btnCommand.pack()
        self.btnCommand.config(command=self.clickCommand)

        self.root.mainloop()
        
    def clickMsg(self, event):
        messagebox.showerror(title='Error!', message='The button is sunken!')
   
    def clickFd(self, event):
        filedialog.askdirectory(title='Choose a directory')
        
    def clickCommand(self):
        messagebox.showinfo(title='Success!', message='The button is raised.')
        
App()
msg130173 - (view) Author: Guilherme Polo (gpolo) * (Python committer) Date: 2011-03-06 15:21
I have a different problem here on Mac, but I can manage to reproduce
your issue if I apply the following patch:

Index: Lib/tkinter/__init__.py
===================================================================
--- Lib/tkinter/__init__.py     (revision 88757)
+++ Lib/tkinter/__init__.py     (working copy)
@@ -920,9 +920,9 @@
             self.tk.call('bindtags', self._w, tagList)
     def _bind(self, what, sequence, func, add, needcleanup=1):
         """Internal function."""
-        if isinstance(func, str):
-            self.tk.call(what + (sequence, func))
-        elif func:
+        #if isinstance(func, str):
+        #    self.tk.call(what + (sequence, func))
+        if func:
             funcid = self._register(func, self._substitute,
                         needcleanup)
             cmd = ('%sif {"[%s %s]" == "break"} break\n'

This should help someone else to produce a patch for this problem you
reported. It is "interesting" that this same patch fixes the problem I
have here (I get a SIGSEGV if I click the cancel button side the
askdirectory dialog).
msg219550 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-06-02 06:11
This is not Tkinter bug, this is normal Tk behavior. Here is minimal reproducer on Tcl/Tk :

    button .b -text "Click me"
    bind .b <Button-1> {tk_messageBox -message "The button is sunken!"}
    pack .b

I suppose the button is left sunken because the message box steals a focus.

In general binding mouse click event for button is not a good idea, because it makes a button non-usable with keyboard. Use the "command" option.
History
Date User Action Args
2014-06-02 06:17:44terry.reedysetstatus: open -> closed
stage: resolved
2014-06-02 06:11:36serhiy.storchakasetresolution: not a bug

messages: + msg219550
nosy: + serhiy.storchaka
2011-03-06 15:21:32gpolosetnosy: terry.reedy, gpolo, Nikolay.Fomichev
messages: + msg130173
2011-03-06 13:50:58Nikolay.Fomichevsetnosy: terry.reedy, gpolo, Nikolay.Fomichev
messages: + msg130170
2011-03-04 23:49:48terry.reedysetnosy: + gpolo, terry.reedy

messages: + msg130088
versions: + Python 3.3, - Python 2.6
2011-03-03 18:30:13Nikolay.Fomichevcreate