user2815547
user2815547

Reputation:

_tkinter.tclerror: bad option set tcl value number must be activate, get, configure

Using Tkinter, I have a button that starts an external thread. And a tkinter Textbox that is piped to the external threads stdout and stderr. I got this error only once while executing the external thread:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
    return self.func(*args)
  File "C:\Python33\lib\tkinter\__init__.py", line 2923, in set
    self.tk.call((self._w, 'set') + args)
_tkinter.TclError: bad option "set TCL VALUE NUMBER": must be activate, cget, configure, delta, fraction, get, identify, or set

Even though it did not occur again, I am curious to find out what caused it. It seems like the error isn't from an external thread but from the main thread that is running the GUI. Could it just be some internal Tkinter error?

Upvotes: 1

Views: 3563

Answers (1)

Graham Bartlett
Graham Bartlett

Reputation: 31

This is probably a bit late, but anyway...

My own research found advice to add 'when="tail"' to the event_generate call, which ensures the event gets queued correctly. If you don't, the Tk event rules can do odd things with the event queue. This is not (yet?) documented in Tkinter.

Even then, my own research (and experience!) has also found that Tkinter is fundamentally not thread-safe. This means that you cannot guarantee that doing anything at all with Tkinter outside its own thread will work. The safest way is to generate events, sure, but even this regularly throws exceptions which indicate the Tkinter internals aren't thread-safed for adding events. Generally these exceptions are survivable, so I use retries to have another crack, and this mostly works.

retries = 3
done = False
unknownException = False
while (retries != 0) and (not done) and (not unknownException):
    try:
        self._applicationWindow.event_generate("<<MyNewEvent>>", when="tail")
        done = True
    except Tk.TclError as err:
        if "application has been destroyed" in err.message:
            # If application is destroyed, this event is not needed
            done = True
        elif ("expected boolean value but got" in err.message) or ("bad option" in err.message): 
            # These are bugs in Tk/Tcl/Tkinter, not in our code.  They seem to be uncommon,
            # and seem to be survivable.  Hopefully retrying will have the system in a
            # slightly different state where this doesn't happen next time.
            print "Tkinter/Tk/Tcl error, retry " + str(retries)
            retries = retries - 1
        else:
            unknownException = True
    except:
        unknownException = True

# Unlock afterwards
self._eventLock.release()

if not done:
    # If retries haven't helped or we have an exception which isn't one we know about,
    # then pass the exception up the tree.
    raise   

A non-thread-safe UI layer is one thing - I guess it simplifies the design, so it's just about acceptable. A non-thread-safe event queue should be a fail grade in your introduction-to-programming class though. If you're concluding that Tkinter is broken and should never be used for any real-world application - join the club. As far as I'm concerned, the correct fix to any Tkinter problem is to use another UI layer which is fit for purpose. :/

PS. I'm using Python 2.7.6. YMMV on Python 3.

Upvotes: 2

Related Questions