[Tkinter-discuss] Tkinter, threads? memory?

On Wed, 20 Sep 2006 12:27:47 -0400
Michael M Haimes <mhaimes at MIT.EDU> wrote:
> ------------1----------
> Linux implementations of Python/Tkinter (the most current) seem to exhibit the
> problem, but not Sun/Solaris or Windows.
>> Essentially, I can't animate objects on a canvas without leaking memory at about
> 1Mb/s . I've tried 4 different methods, either deleting and redrawing objects,
> or just moving objects, and either using Tk tags to label and operate the
> objects, or storing their IDs in my program and operating with them that way. I
> can't think of any other way to do this, and I basically need to. I would try
> the WCK to make my own, but the idea is to have the software run on a base
> install of Python.
>> The link to the four example test scripts I wrote up is here:
>http://web.mit.edu/mhaimes/Public/tktest.tar>> ------------2----------
> The Mac OS X implementation of Python seems to exhibit this problem, and no
> other systems.
>> This problem is related to the above, namely, on the Mac animation seems to be
> totally broken. Whenever Tk is running its event loop, it stops all other
> python threads from processing and sits and waits for input. So my example code
> below runs a counter in a background thread which increments the number Tk has
> displayed. On Windows/Linux, it just counts up until you press exit. On the
> Mac, it will sit there and freeze if you aren't inputting anything, but as soon
> as you wave the mouse around or start typing it'll continue to increment;
> whereas on Windows and Linux, the counter just counts up no matter what you are
> inputting. I know this could be done without two separate threads, but the real
> program that this is modelling an issue I'm having needs Tk to be in its event
> loop, so that is not an option.
>> Test code as follows:
> #################
> import Tkinter
> import thread
> import sys
>> app = Tkinter.Tk()
> text = Tkinter.StringVar()
> Tkinter.Label(app, textvariable = text).pack()
> def looper():
> count = 0
> while 1:
> text.set(`count`)
> count+=1
> thread.start_new_thread(looper, ())
> Tkinter.Button(app, text="exit", command = sys.exit).pack()
> app.mainloop()
> ##############
>> -----------------------
>> If anyone has any hints or suggestions for workarounds for either of the above
> problems, it would be much appreciated. Or if you just run any of the test
> programs on your systems and get different results than I predicted for you,
> tell me some things about your system and what happened.
>
Hi Michael,
for me (on linux) #2 works, on all examples of #1 i get this error:
Unhandled exception in thread started by <function mover at 0xb7dbf684>
Traceback (most recent call last):
File "projekte/test2.py", line 18, in mover
canvas.move(dot, -100*sin(t)*dt, 100*cos(t)*dt)
File "/usr/lib/python2.4/lib-tk/Tkinter.py", line 2189, in move
self.tk.call((self._w, 'move') + args)
_tkinter.TclError: too many nested evaluations (infinite loop?)
Generally I don't think it is a good idea to update Tk widgets directly from
Python threads. I think you better create some variable to manage the communication
between Tk and your child thread, as in this example which does practcally the same
as #2:
import Tkinter
import thread
import sys
app = Tkinter.Tk()
text = Tkinter.StringVar()
Tkinter.Label(app, textvariable = text).pack()
newtext = '0'
def looper():
global newtext
count = 0
while 1:
#text.set(`count`)
newtext = str(count)
count+=1
thread.start_new_thread(looper, ())
Tkinter.Button(app, text="exit", command = sys.exit).pack()
def update_label():
text.set(newtext)
app.after(10, update_label)
update_label()
app.mainloop()
And a working animation as in #1 with the same technique:
import Tkinter
from time import time, sleep
from math import sin, cos
from thread import start_new_thread
import sys
app = Tkinter.Tk()
canvas = Tkinter.Canvas(app, width=300, height=300)
canvas.pack()
t = time()
dot = canvas.create_oval(100*cos(t)+150, 100*sin(t)+150, 100*cos(t)+150, 100*sin(t)+150)
x, y = 0, 0
def mover():
global x, y
t = time()
try:
while 1:
dt = time()-t;t=time()
#canvas.move(dot, -100*sin(t)*dt, 100*cos(t)*dt)
x, y = -100*sin(t)*dt, 100*cos(t)*dt
sleep(0.1)
except KeyboardInterrupt:
sys.exit(-1)
start_new_thread(mover, ())
def update_oval():
canvas.move(dot, x, y)
canvas.after(100, update_oval)
update_oval()
app.mainloop()
I hope this helps
Michael