Tkinter: update_idletasks

Discussion in 'Python' started by Jeffrey Barish, May 20, 2004.

  1. 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
     
    Jeffrey Barish, May 20, 2004
    #1
    1. Advertising

  2. In article <>,
    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?


    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
     
    Russell E. Owen, May 20, 2004
    #2
    1. Advertising

  3. Jeffrey Barish

    Eric Brunel Guest

    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
     
    Eric Brunel, May 21, 2004
    #3
  4. 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
     
    Jeffrey Barish, May 21, 2004
    #4
  5. Jeffrey Barish

    klappnase Guest

    Jeffrey Barish <> wrote in message news:<>...

    > 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
     
    klappnase, May 22, 2004
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jeff Epler
    Replies:
    0
    Views:
    510
    Jeff Epler
    Aug 20, 2004
  2. Jeff Epler
    Replies:
    0
    Views:
    459
    Jeff Epler
    Aug 23, 2004
  3. Pierre Dagenais
    Replies:
    0
    Views:
    318
    Pierre Dagenais
    Aug 3, 2008
  4. Hidekazu IWAKI
    Replies:
    1
    Views:
    384
    Peter Otten
    Dec 14, 2009
  5. Hidekazu IWAKI
    Replies:
    0
    Views:
    527
    Hidekazu IWAKI
    Dec 15, 2009
Loading...

Share This Page