By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,908 Members | 1,892 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,908 IT Pros & Developers. It's quick & easy.

Tkinter: update_idletasks

P: n/a
I'm confused about how to use the update_idletasks method. In my
program, I have a handler for a button in which execution will linger.
During that time, I would like for the GUI to continue to show signs of
life. I have a Pmw MessageBar in which I display a status message. I
figured out that if I run update_idletasks on that MessageBar, then the
MessageBar will update the display as I update the message. However,
if I cover the GUI with some other window and then expose it again, the
GUI does not refresh until the handler finishes (except for the
MessageBar). Do I have to run the update_idletasks method for every
widget in the GUI? for all the frames? for just the root frame? Or is
it impossible to get the GUI to refresh in this situation?
--
Jeffrey Barish
Jul 18 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
In article <ma*************************************@python.or g>,
Jeffrey Barish <je********@starband.net> wrote:
I'm confused about how to use the update_idletasks method. In my
program, I have a handler for a button in which execution will linger.
During that time, I would like for the GUI to continue to show signs of
life. I have a Pmw MessageBar in which I display a status message. I
figured out that if I run update_idletasks on that MessageBar, then the
MessageBar will update the display as I update the message. However,
if I cover the GUI with some other window and then expose it again, the
GUI does not refresh until the handler finishes (except for the
MessageBar). Do I have to run the update_idletasks method for every
widget in the GUI? for all the frames? for just the root frame? Or is
it impossible to get the GUI to refresh in this situation?


To make your GUI responsive, call update_idletasks occasionally from the
task that is taking a long time. Like most GUI systems, Tkinter is
basically a single threaded system. It'll run the current task until
finished, then process the next event. update_idletasks gives it a
chance to handle other events.

There are other ways to handle this sort of thing. Typically a
long-running task should be run as a separate background thread (or even
a separate process). The difficulty is that background threads cannot
safely interact with GUI elements, so how does the thread communicate?

The most straightforward technique is to transfer data from the
background thread to the main thread via a Queue object (as usual), then
poll the background thread's Queue (by repeatedly calling after to do a
nonblocking read on the Queue object).

However, a clever trick posted fairly recently is to have the background
thread generate an event. Apparently that is safe. Then have a handler
listen for that event. The handler will run in the main thread, and so
can safely update the GUI.

-- Russell
Jul 18 '05 #2

P: n/a
Jeffrey Barish wrote:
I'm confused about how to use the update_idletasks method. In my
program, I have a handler for a button in which execution will linger.
During that time, I would like for the GUI to continue to show signs of
life. I have a Pmw MessageBar in which I display a status message. I
figured out that if I run update_idletasks on that MessageBar, then the
MessageBar will update the display as I update the message. However,
if I cover the GUI with some other window and then expose it again, the
GUI does not refresh until the handler finishes (except for the
MessageBar). Do I have to run the update_idletasks method for every
widget in the GUI? for all the frames? for just the root frame? Or is
it impossible to get the GUI to refresh in this situation?


At tcl level, update_idletasks isn't a "method", i.e. the tcl command doesn't
take any parameter telling which widget to refresh. So calling the Tkinter
update_idletasks method on any widget has exactly the same effect, which is to
refresh the whole GUI.

There are some issues on Windows however, where the newly created toplevel's may
not refresh until full control is returned to the GUI. To work around this
problem, use the wait_visibility method to wait until the newly created window
is displayed. But be careful: wait_visibility processes events, unlike
update_idletasks that does just a GUI refresh. There is apparently no simple way
of updating the display of newly created toplevel's on Windows without returning
full control to the GUI (at least with tk/Tkinter)

I never saw the problem you describe (some windows refreshing, some not), but I
mainly develop on Linux, which may show a different behaviour than the platform
you're working on (which BTW you don't mention...). Maybe you can post a small
piece of code showing the problem?

HTH
--
- Eric Brunel <eric (underscore) brunel (at) despammed (dot) com> -
PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com

Jul 18 '05 #3

P: n/a
Eric Brunel wrote:
Jeffrey Barish wrote:
I'm confused about how to use the update_idletasks method. In my
program, I have a handler for a button in which execution will
linger. During that time, I would like for the GUI to continue to
show signs of
life. I have a Pmw MessageBar in which I display a status message.
I figured out that if I run update_idletasks on that MessageBar, then
the
MessageBar will update the display as I update the message. However,
if I cover the GUI with some other window and then expose it again,
the GUI does not refresh until the handler finishes (except for the
MessageBar). Do I have to run the update_idletasks method for every
widget in the GUI? for all the frames? for just the root frame? Or
is it impossible to get the GUI to refresh in this situation?


At tcl level, update_idletasks isn't a "method", i.e. the tcl command
doesn't take any parameter telling which widget to refresh. So calling
the Tkinter update_idletasks method on any widget has exactly the same
effect, which is to refresh the whole GUI.

There are some issues on Windows however, where the newly created
toplevel's may not refresh until full control is returned to the GUI.
To work around this problem, use the wait_visibility method to wait
until the newly created window is displayed. But be careful:
wait_visibility processes events, unlike update_idletasks that does
just a GUI refresh. There is apparently no simple way of updating the
display of newly created toplevel's on Windows without returning full
control to the GUI (at least with tk/Tkinter)

I never saw the problem you describe (some windows refreshing, some
not), but I mainly develop on Linux, which may show a different
behaviour than the platform you're working on (which BTW you don't
mention...). Maybe you can post a small piece of code showing the
problem?

HTH

Ah. I had a hunch that might be the case. However, that is not the
behavior that I am seeing. First, in response to your questions: (1) I
am on Linux (there are other platforms?); (2) I am using Python 2.3;
(3) it is difficult to extract a piece of the code, but I will attempt
to describe more clearly what I am doing. There is a button with a
handler. In the handler I use popen3 to launch a program that takes a
long time to execute. I monitor its progress in a while loop by
reading a status line that it produces on stderr. The status line
provides information about percentage complete; I use that information
to update the MessageBar in my GUI. When the status line indicates
that the process is done, I exit the while loop and return from the
button handler. I tried running update_idletasks on the MessageBar in
the while loop. I tried running it on the root window, even though the
information you provided indicated that it doesn't matter what class
owns the method -- and my experience certainly does not contradict that
statement. In every case, only the MessageBar updates. Well, that's
not entirely true. I also move a tag in a text widget; the previously
and newly tagged text redraws. The only technique I have found that
permits the main window to update is to run most of the handler in a
separate thread. The problem I am having with that approach is that
the MessageBar then flashes in an annoying way (the background seems to
go to white at every update and then gets redrawn to gray -- which
happens only when the while loop is in its own thread). Any other
thoughts would be much appreciated.
--
Jeffrey Barish
Jul 18 '05 #4

P: n/a
Jeffrey Barish <je********@starband.net> wrote in message news:<ma*************************************@pyth on.org>...
Ah. I had a hunch that might be the case. However, that is not the
behavior that I am seeing. First, in response to your questions: (1) I
am on Linux (there are other platforms?); (2) I am using Python 2.3;
(3) it is difficult to extract a piece of the code, but I will attempt
to describe more clearly what I am doing. There is a button with a
handler. In the handler I use popen3 to launch a program that takes a
long time to execute. I monitor its progress in a while loop by
reading a status line that it produces on stderr. The status line
provides information about percentage complete; I use that information
to update the MessageBar in my GUI. When the status line indicates
that the process is done, I exit the while loop and return from the
button handler. I tried running update_idletasks on the MessageBar in
the while loop. I tried running it on the root window, even though the
information you provided indicated that it doesn't matter what class
owns the method -- and my experience certainly does not contradict that
statement. In every case, only the MessageBar updates. Well, that's
not entirely true. I also move a tag in a text widget; the previously
and newly tagged text redraws. The only technique I have found that
permits the main window to update is to run most of the handler in a
separate thread. The problem I am having with that approach is that
the MessageBar then flashes in an annoying way (the background seems to
go to white at every update and then gets redrawn to gray -- which
happens only when the while loop is in its own thread). Any other
thoughts would be much appreciated.


I've been using a Tkinter filehandler for similar tasks and didn't
have the problems you describe.
Here's a pseudo-code snippet to illustrate what I did:

from Tkinter import *
import os, fcntl, popen2

def button_callback(self, event):
#the function that's bound to the button
#dialog window with progress bar:
self.pw = ProgressWindow.ProgressWindow()
selectedfiles = ' '.join(tracklist)
normalizecmd = 'exec normalize -m ' + selectedfiles
self.pp = popen2.Popen4(normalizecmd)
self.mkfilehandler(self.pp, self.getprogress)

def mkfilehandler(self, popen4object, function):
#creates the filehandler
fileobject = popen4object.fromchild
filedescr = fileobject.fileno()
fcntl.fcntl(filedescr, fcntl.F_SETFL, os.O_NONBLOCK)
tkinter.createfilehandler(fileobject, READABLE, function)

def getprogress(self, fileobject, event_type):
message = self.pp.fromchild.read()
if message == '':
# process has finished
# this could be checked with "if self.pp.poll() != -1:" either
tkinter.deletefilehandler(self.pp.fromchild)
<...clean up stuff here...>
self.pp = None
else:
<...parse the output messages, extract progress values,
etc....>
# update the progress bar (update_idletasks() is called from
it's set() method):
self.pw.set(value=progress)

I hope this helps

Michael
Jul 18 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.