Weird ttk behaviour

R

Rotwang

Hi all,

I've just started trying to learn how to use ttk, and I've discovered
something that I don't understand. I'm using Python 3.3.0 in Linux Mint
15. Suppose I create the following module:

# begin tkderp.py

import tkinter as tk
import tkinter.messagebox as _
from tkinter import ttk
from imp import reload


_root = tk.Tk()
_root.withdraw()

def f():
style = ttk.Style(_root)
style.theme_create('newtheme', parent = 'default')
tk.messagebox.showwarning('test', 'test')
style.theme_use('newtheme')
tk.messagebox.showwarning('test', 'test')

# end tkderp.py


The function f() is supposed to spawn two warning dialogs. AIUI, the
"style.theme.use('newtheme')" line shouldn't make any difference - it
would refresh any existing ttk widgets and alter the appearance of any
subsequently created ones if I had changed any of the new theme's
settings, but in the above context nothing it does should be discernible
to the user. If I try to call f() the first warning gets shown, but the
second one causes an exception:

Python 3.3.1 (default, Apr 17 2013, 22:30:32)
[GCC 4.7.3] on linux
Type "help", "copyright", "credits" or "license" for more information.Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/phil/Python/tkderp.py", line 17, in f
tk.messagebox.showwarning('test', 'test')
File "/usr/lib/python3.3/tkinter/messagebox.py", line 87, in showwarning
return _show(title, message, WARNING, OK, **options)
File "/usr/lib/python3.3/tkinter/messagebox.py", line 72, in _show
res = Message(**options).show()
File "/usr/lib/python3.3/tkinter/commondialog.py", line 48, in show
s = w.tk.call(self.command, *w._options(self.options))
_tkinter.TclError: unknown color name ""


If I try reloading the module and calling the function again, this time
the first of the two warnings raises the exception. Since I don't really
understand how the ttk.Style class works, I can't say whether this
behaviour is expected or not. But here's what's weird. Suppose that I
comment out the last two lines in the definition of f(), like so:

# begin modified tkderp.py

import tkinter as tk
import tkinter.messagebox as _
from tkinter import ttk
from imp import reload


_root = tk.Tk()
_root.withdraw()

def f():
style = ttk.Style(_root)
style.theme_create('newtheme', parent = 'default')
tk.messagebox.showwarning('test', 'test')
#style.theme_use('newtheme')
#tk.messagebox.showwarning('test', 'test')

# end modified tkderp.py


Unsurprisingly, importing the module and calling f() displays a single
warning dialog and raises no exception. If I then uncomment those two
lines, reload the module and call f() again (by entering
tkderp.reload(tkderp).f()), the function works like it was supposed to
in the first place: two warnings, no exceptions. I can reload the module
as many times as I like and f() will continue to work without any problems.

On Windows 7 (sys.version is '3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012,
10:57:17) [MSC v.1600 64 bit (AMD64)]') there's no problem; f() works
fine in the first place. Does anybody know what's going on?
 
S

Serhiy Storchaka

16.09.13 19:28, Rotwang напиÑав(ла):
On Windows 7 (sys.version is '3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012,
10:57:17) [MSC v.1600 64 bit (AMD64)]') there's no problem; f() works
fine in the first place. Does anybody know what's going on?

What _root.wantobjects() returns?
 
C

Chris Angelico

If I then uncomment those two lines, reload the module and call f() again
(by entering tkderp.reload(tkderp).f()), the function works like it was
supposed to in the first place: two warnings, no exceptions. I can reload
the module as many times as I like and f() will continue to work without any
problems.

Reloading modules in Python is a bit messy. Are you able to tinker
with it and make it work in some way without reloading? It'd be easier
to figure out what's going on that way.

ChrisA
 
R

Rotwang

16.09.13 19:28, Rotwang напиÑав(ла):
On Windows 7 (sys.version is '3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012,
10:57:17) [MSC v.1600 64 bit (AMD64)]') there's no problem; f() works
fine in the first place. Does anybody know what's going on?

What _root.wantobjects() returns?

It returns True, both before and after the call to
style.theme_use('newtheme'). Why do you ask? I've no idea what
Tk.wantobjects is supposed to do (I tried help() and some web searches
with no luck).
 
R

Rotwang

Reloading modules in Python is a bit messy. Are you able to tinker
with it and make it work in some way without reloading? It'd be easier
to figure out what's going on that way.

I can't think what else I could try, do you have any suggestions? The
problem first appeared in a much larger module (I was trying to replace
some tkinter widgets that looked bad on Linux with their ttk
equivalents); the only reason I noticed the thing about reloading is
that I was trying to reproduce the error in a short module by repeatedly
making changes and reloading.
 
C

Chris Angelico

I can't think what else I could try, do you have any suggestions? The
problem first appeared in a much larger module (I was trying to replace some
tkinter widgets that looked bad on Linux with their ttk equivalents); the
only reason I noticed the thing about reloading is that I was trying to
reproduce the error in a short module by repeatedly making changes and
reloading.

If reloading and doing it again makes things different, what happens
if you simply trigger your code twice without reloading?

I've no idea if it'll help, it just seems like an attack vector on the
problem, so to speak.

ChrisA
 
R

Rotwang

[...]

If reloading and doing it again makes things different, what happens
if you simply trigger your code twice without reloading?

I've no idea if it'll help, it just seems like an attack vector on the
problem, so to speak.

Thanks for the suggestion, here's what I've found with some more
testing. If I rewrite the function f() like this:

def f(fail):
style = ttk.Style(_root)
style.theme_create('newtheme', parent = 'default')
tk.messagebox.showwarning('test', 'test')
if fail:
style.theme_use('newtheme')
tk.messagebox.showwarning('test', 'test')


then I import the module and call f(False) followed by f(True), the
second call raises an exception just like the original function. I've
tried variations of the above, such as defining a module-level global
style instead of having one created during the function call, and the
end result is always the same. However, suppose instead I define two
modules, tkderp and tkderp2; both have a function f as defined in my OP,
but the first has the last two lines of f commented out, and the second
doesn't (i.e. tkderp is the modified tkderp from before, and tkderp2 is
the original). Then I do this:


In that case the second call to f() works fine - two warnings, no
exception. In fact, if I replace tkderp with this:

# begin tkderp.py

import tkinter as tk

_root = tk.Tk()
_root.withdraw()

# end tkderp.py


then simply importing tkderp before tkderp2 is enough to make the latter
work properly - this


raises an exception, but this


doesn't. Any ideas what may be going on?
 
C

Chris Angelico

In fact, if I replace tkderp with this:


# begin tkderp.py

import tkinter as tk

_root = tk.Tk()
_root.withdraw()

# end tkderp.py


then simply importing tkderp before tkderp2 is enough to make the latter
work properly

Nice piece of detective work! Alas, I don't know tkinter well enough
to help with the details, but this is exactly what I'd like to hear if
I were trying to pick this up and debug it :)

Tkinter experts, anywhere? Where's Ranting Rick when you need him...

ChrisA
 
R

Rotwang

Nice piece of detective work! Alas, I don't know tkinter well enough
to help with the details, but this is exactly what I'd like to hear if
I were trying to pick this up and debug it :)

I don't know tkinter well enough either, but the fact that it behaves
differently on Linux and Windows suggests to me that at least one
version is bugging out. Do you think this is worth raising on
bugs.python.org?

Tkinter experts, anywhere? Where's Ranting Rick when you need him...

Last time I saw him was in this thread:

https://mail.python.org/pipermail/python-list/2013-June/650257.html
 
C

Chris Angelico

I don't know tkinter well enough either, but the fact that it behaves
differently on Linux and Windows suggests to me that at least one version is
bugging out. Do you think this is worth raising on bugs.python.org?

Possibly, but I'd keep it here on python-list for the moment; it may
be you're actually using undefined behaviour somewhere, in which case
the solution is to change your code. Once someone else (someone who
actually knows what he's talking about, for preference) can confirm
what's going on, it'll be bug report time, I think.

ChrisA
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top