Multithreading tkinter question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mark English

    #1

    Multithreading tkinter question

    Is there a safe way to run tkinter in a multithreaded app where the
    mainloop runs in a background thread ?
    Here's some test code demonstrating the problem. I'm running Python2.4
    under Windows 2000.


    ----------------Code snip starts-------------
    from Tkinter import *

    def GetTkinterThrea d():
    import threading
    def TestTkinter():
    def greeting():
    print "Hello stdout world !"

    win = Frame()
    win.pack()
    Label(win, text="Hello container world").pack(si de=TOP)
    Button(win, text="Hello", command=greetin g).pack(side=TO P)
    Button(win, text="Quit", command=win.qui t).pack(side=RI GHT)

    win.mainloop()
    #Run the mainloop in another thread
    t = threading.Threa d(None, TestTkinter, 'Test Tkinter Thread')
    t.setDaemon(1) #Keep going
    t.start()
    print 'Hi'
    return t

    t = GetTkinterThrea d() #This works fine

    #Now press the "Hello" button on the Tkinter window
    #Now press the return key at the python prompt

    ----------------Code snip ends-------------
    With a debug build the call stack looks like this:
    python24_d.dll! Py_FatalError(c onst char * msg=0x1e23ca14) Line
    1513 C
    python24_d.dll! PyThreadState_S wap(_ts * new=0x0098d0b8) Line
    293 + 0xa C
    python24_d.dll! PyEval_RestoreT hread(_ts * tstate=0x0098d0 b8)
    Line 309 + 0x9 C
    _tkinter_d.pyd! EventHook() Line 2969 + 0xc C
    python24_d.dll! my_fgets(char * buf=0x009ef3e8, int len=100,
    _iobuf * fp=0x1027c838) Line 46 C
    python24_d.dll! PyOS_StdioReadl ine(_iobuf * sys_stdin=0x102 7c838,
    _iobuf * sys_stdout=0x10 27c858, char * prompt=0x0087f9 74) Line 125 +
    0x11 C
    python24_d.dll! PyOS_Readline(_ iobuf * sys_stdin=0x102 7c838,
    _iobuf * sys_stdout=0x10 27c858, char * prompt=0x0087f9 74) Line 205 +
    0x12 C

    Is this because of access to sys.stdout ? Or some deeper darker problem
    ? Is there a right way to achieve this ? Basically I want to be able to
    call a function from the Python prompt which creates a Tkinter window
    (not necessarily interactive apart from a close button) to display some
    data, but leaves the Python prompt active so I can carry on from there.

    Haven't found anything about this yet. All sample multithreaded Tkinter
    code I've seen uses the main thread as the GUI thread. Also, should I be
    posting this to another newsgroup ?

    Thanks for any help,
    Mark


    -----------------------------------------------------------------------
    The information contained in this e-mail is confidential and solely
    for the intended addressee(s). Unauthorised reproduction, disclosure,
    modification, and/or distribution of this email may be unlawful. If you
    have received this email in error, please notify the sender immediately
    and delete it from your system. The views expressed in this message
    do not necessarily reflect those of LIFFE Holdings Plc or any of its subsidiary companies.
    -----------------------------------------------------------------------

  • Oleg  Paraschenko

    #2
    Re: Multithreading tkinter question

    Hello John,
    [color=blue]
    > Mark,
    >
    > I tried your code snippet with Python 2.3.4. Worked fine. Only[/color]
    problem was[color=blue]
    > that the program fell off the end and terminated before the second[/color]
    thread[color=blue]
    > could open the Tkinter window. So I added these lines at the end to[/color]
    make the[color=blue]
    > main thread wait:-
    >
    > from msvcrt import kbhit, getch
    > print "\n\nPress key to end"
    > while not kbhit(): pass
    > getch()[/color]

    And I added

    print "\n\nPress key to end"
    l = sys.stdin.readl ine()
    [color=blue]
    > Both your Hello and Quit buttons worked.[/color]

    In my case "Hello" works and "Quit" doesn't (GUI stays frozen).
    Linux, Python 2.3.3, pygtk-0.6.9.
    [color=blue]
    > ...
    >
    > It is not optimal in that 'otherThread' runs continuously even when[/color]
    the[color=blue]
    > label is not being updated. What a waste of cpu cycles! This shows up[/color]
    in[color=blue]
    > that other windows apps slow right down. What is needed is a comms[/color]
    method[color=blue]
    > between threads that causes a thread to block while it's waiting for[/color]
    data[color=blue]
    > rather than my continuous polling approach. Would a Queue help here?
    >[/color]

    Yes, it should help. A time ago I tried to write a tkinter
    application,
    and my test code is available:

    A complete Python Tkinter sample application for a long operation

    Maybe you find it interesting.

    --
    Oleg

    Comment

    • Eric Brunel

      #3
      Re: Multithreading tkinter question

      Oleg Paraschenko wrote:
      [snip][color=blue]
      > In my case "Hello" works and "Quit" doesn't (GUI stays frozen).
      > Linux, Python 2.3.3, pygtk-0.6.9.[/color]

      That's not a multithreading issue, but just the way the quit method works. Try:

      -------------------------------------------------
      import time
      from Tkinter import *

      root = Tk()
      b = Button(root, text='Quit')
      b.configure(com mand=root.quit)
      b.pack()

      root.mainloop()

      time.sleep(2)
      -------------------------------------------------

      When you click the "Quit" button, the GUI stays there until the time.sleep ends.
      root.quit just goes out of the mainloop; it doesn't destroy the widgets. To do
      that, you have to add an explicit root.destroy() after root.mainloop()
      --
      - Eric Brunel <eric (underscore) brunel (at) despammed (dot) com> -
      PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com

      Comment

      Working...