Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run a function in the background of tkinter

Tags:

python

tkinter

I am new to GUI programming and I want to write a Python program with tkinter. All I want it to do is run a simple function in the background that can be influenced through the GUI.

The function counts from 0 to infinity until a button is pressed. At least that is what I want it to do. But I have no idea how I can run this function in the background, because the mainloop() of tkinter has control all the time. And if I start the function in an endless loop, the mainloop() cannot be executed and the GUI is dead.

I would like to return control back to the mainloop() after each cycle, but how can I get the control back from the mainloop() to the runapp-function without a user-triggered event?

Here is some sample code that kills the GUI:

from Tkinter import *

class App:
    def __init__(self, master):

        frame = Frame(master)
        frame.pack()

        self.button = Button(frame, text="START", command=self.runapp)
        self.button.pack(side=LEFT)

        self.hi_there = Button(frame, text="RESTART", command=self.restart)
        self.hi_there.pack(side=LEFT)

        self.runapp()

    def restart(self):
        print "Now we are restarting..."

    def runapp(self):
        counter = 0
        while (1):
            counter =+ 1
            time.sleep(0.1)
like image 312
Demento Avatar asked Feb 19 '11 00:02

Demento


3 Answers

Event based programming is conceptually simple. Just imagine that at the end of your program file is a simple infinite loop:

while <we have not been told to exit>:
    <pull an event off of the queue>
    <process the event>

So, all you need to do to run some small task continually is break it down into bite-sized pieces and place those pieces on the event queue. Each time through the loop the next iteration of your calculation will be performed automatically.

You can place objects on the event queue with the after method. So, create a method that increments the number, then reschedules itself to run a few milliseconds later. It would look something like:

def add_one(self):
    self.counter += 1
    self.after(1000, self.add_one)

The above will update the counter once a second. When your program initializes you call it once, and from then after it causes itself to be called again and again, etc.

This method only works if you can break your large problem (in your case "count forever") into small steps ("add one"). If you are doing something like a slow database query or huge computation this technique won't necessarily work.

like image 175
Bryan Oakley Avatar answered Jan 01 '23 22:01

Bryan Oakley


Try to understand this example : clock updating in backgroud, and updating GUI ( no need for 2 threads ).

# use Tkinter to show a digital clock
# tested with Python24    vegaseat    10sep2006
from Tkinter import *
import time
root = Tk()
time1 = ''
clock = Label(root, font=('times', 20, 'bold'), bg='green')
clock.pack(fill=BOTH, expand=1)
def tick():
    global time1
    # get the current local time from the PC
    time2 = time.strftime('%H:%M:%S')
    # if time string has changed, update it
    if time2 != time1:
        time1 = time2
        clock.config(text=time2)
    # calls itself every 200 milliseconds
    # to update the time display as needed
    # could use >200 ms, but display gets jerky
    clock.after(200, tick)
tick()
root.mainloop(  )

credits: link to site

like image 35
guyd Avatar answered Jan 01 '23 22:01

guyd


You will find the answer in this other question Tkinter locks python when Icon loaded and tk.mainloop in a thread.

In a nutshell, you need to have two threads, one for tkinter and one for the background task.

like image 41
Michael Dillon Avatar answered Jan 01 '23 23:01

Michael Dillon