tkinter redraw rates

Christian Gollwitzer auriocus at gmx.de
Thu Jul 18 09:20:28 CEST 2013


Am 18.07.13 06:38, schrieb fronagzen at gmail.com:
> On Thursday, July 18, 2013 9:07:24 AM UTC+8, Dave Angel wrote:
>> Nope - don't use that.  Instead, post an event on the queue, and return
>> to the mainloop() from whence we came.
>>           def test_thread(self):
>>              if self.loader_thread.isAlive():
>>                  self.root_window.after(100, self.test_thread)
>>                  return
>

> I see, though it should be noted that your method doesn't actually
> block the rest of the even handler code from running, had to fiddle
> with it a bit to get that to work. May I ask what exactly is the
> rationale behind implementing it like this, though?
>

Exactly this is the goal of it. Event handlers are supposed to run in as 
short time as possible, and should never block. The reason is that you 
want the events to be processed in the order they come in, such that he 
user can still move the window, resize it, iconify/maximize etc.

That said, the code still looks odd to me. I have used the Tk with 
multithreading in the past, but directly from Tcl, and not from Python.
The basic idea is to have the background thread (which does the work) 
signal the main thread about its status, i.e. in the worker thread:

for i in range(50):
   some_odd_computation()
   signal('progress', i)

signal('finished')

and in the main thread you bind() to the events fired from the worker 
thread. That way you don't run any periodic polling.

I fear that Tkinter has a shortcoming which does not allow this pattern 
to be implemented. The tricky thing is to implement this signal() 
function, which must post an event to another thread. From the C level, 
there is Tcl_ThreadQueueEvent() which does this. It arranges for a C 
function to be run from the event loop of another thread. From Tcl, 
thread::send does this. To use it from Tkinter, it would be necessary to 
create a Tcl interpreter in the worker thread *without* loading Tk.

Some day I should dive into the innards of Tkinter to see if this is 
possible. Then you could implement signal() simply by

def signal(sig, data=''):
	tclinterp.eval('thread::send -async $mainthread {event generate . 
<<%s>> -data {%s}'%sig%data)

and in the main thread bind() to the virtual events.

	Christian





More information about the Python-list mailing list