Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>To understand the 'freezing' you need to understand <a href="http://effbot.org/tkinterbook/widget.htm#Tkinter.Widget.mainloop-method" rel="noreferrer"><code>mainloop()</code></a>. Calling this method starts the <em>tkinter</em> event loop. The main thread is responsible for this loop. Therefore, when your work intensive function runs in the main thread, it is also interfering with the mainloop. To prevent this you can use a secondary <a href="http://docs.python.org/3.3/library/threading.html?highlight=threading#thread-objects" rel="noreferrer"><code>Thread</code></a> to run your function. It's recommended that secondary threads are not given access to tkinter objects. Allen B.Taylor, author of <a href="http://tkinter.unpythonic.net/wiki/mtTkinter" rel="noreferrer">mtTkinter</a>, states:</p> <blockquote> <p>The problems stem from the fact that the _tkinter module attempts to gain control of the main thread via a polling technique when processing calls from other threads. If it succeeds, all is well. If it fails (i.e., after a timeout), the application receives an exception with the message: "RuntimeError: main thread is not in main loop".</p> </blockquote> <p>You can have the secondary thread put information into a <a href="http://docs.python.org/3.3/library/queue.html?highlight=queue#queue.Queue" rel="noreferrer"><code>Queue</code></a>. Then have a function that checks the <em>Queue</em> every <em>x</em> milliseconds, within the mainloop, via the <a href="http://effbot.org/tkinterbook/widget.htm#Tkinter.Widget.after-method" rel="noreferrer"><code>after()</code></a> method.</p> <p>First, decide what you want the value of the <em>Progressbar</em>'s <a href="http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-Progressbar.html" rel="noreferrer">maximum</a> option to be.<br> This is the Progressbar's maximum indicator value (how many units are required to fill the Progressbar). For example, you could set <code>maximum=4</code> and then put the appropriate indicator value into the Queue after each of your four functions. The main thread can then retrieve these values (from the Queue) to set the progress via a <code>tkinter.IntVar()</code>. (Note that if you use <code>progbar.step()</code>, the Progressbar resets to 0 (empty) at the end, instead of reaching 4 (completely filled).) </p> <p>Here's a quick look at how you can use a <code>tkinter.IntVar()</code> with a Progressbar:</p> <pre><code>int_var = tkinter.IntVar() pb_instance = ttk.Progressbar(root, maximum=4) pb_instance['variable'] = int_var pb_instance.pack() # completely fill the Progressbar int_var.set(4) # get the progress value x = int_var.get() </code></pre> <p>Here's an example based on your own (renamed the "main" function "arbitrary"):</p> <pre><code>import time import threading try: import tkinter except ImportError: import Tkinter as tkinter import ttk import Queue as queue else: from tkinter import ttk import queue class GUI_Core(object): def __init__(self): self.root = tkinter.Tk() self.int_var = tkinter.IntVar() progbar = ttk.Progressbar(self.root, maximum=4) # associate self.int_var with the progress value progbar['variable'] = self.int_var progbar.pack() self.label = ttk.Label(self.root, text='0/4') self.label.pack() self.b_start = ttk.Button(self.root, text='Start') self.b_start['command'] = self.start_thread self.b_start.pack() def start_thread(self): self.b_start['state'] = 'disable' self.int_var.set(0) # empty the Progressbar self.label['text'] = '0/4' # create then start a secondary thread to run arbitrary() self.secondary_thread = threading.Thread(target=arbitrary) self.secondary_thread.start() # check the Queue in 50ms self.root.after(50, self.check_que) def check_que(self): while True: try: x = que.get_nowait() except queue.Empty: self.root.after(25, self.check_que) break else: # continue from the try suite self.label['text'] = '{}/4'.format(x) self.int_var.set(x) if x == 4: self.b_start['state'] = 'normal' break def func_a(): time.sleep(1) # simulate some work def func_b(): time.sleep(0.3) def func_c(): time.sleep(0.9) def func_d(): time.sleep(0.6) def arbitrary(): func_a() que.put(1) func_b() que.put(2) func_c() que.put(3) func_d() que.put(4) que = queue.Queue() gui = GUI_Core() # see GUI_Core's __init__ method gui.root.mainloop() </code></pre> <p>If all you want is something that indicates to the user that there is activity<br> you can set the Progressbar's <a href="http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-Progressbar.html" rel="noreferrer">mode</a> option to <code>'indeterminate'</code>.<br> The indicator bounces back and forth in this mode (the speed relates to the maximum option). </p> <p>Then you can call the Progressbar's <code>start()</code> method directly before starting the secondary thread;<br> and then call <code>stop()</code> after <code>secondary_thread.is_alive()</code> returns <em>False</em>.</p> <p>Here's an example:</p> <pre><code>import time import threading try: import tkinter except ImportError: import Tkinter as tkinter import ttk else: from tkinter import ttk class GUI_Core(object): def __init__(self): self.root = tkinter.Tk() self.progbar = ttk.Progressbar(self.root) self.progbar.config(maximum=4, mode='indeterminate') self.progbar.pack() self.b_start = ttk.Button(self.root, text='Start') self.b_start['command'] = self.start_thread self.b_start.pack() def start_thread(self): self.b_start['state'] = 'disable' self.progbar.start() self.secondary_thread = threading.Thread(target=arbitrary) self.secondary_thread.start() self.root.after(50, self.check_thread) def check_thread(self): if self.secondary_thread.is_alive(): self.root.after(50, self.check_thread) else: self.progbar.stop() self.b_start['state'] = 'normal' def func_a(): time.sleep(1) # simulate some work def func_b(): time.sleep(0.3) def func_c(): time.sleep(0.9) def func_d(): time.sleep(0.6) def arbitrary(): func_a() func_b() func_c() func_d() gui = GUI_Core() gui.root.mainloop() </code></pre> <p>→ <a href="http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-Progressbar.html" rel="noreferrer">Progressbar reference</a></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload