Как запустить функцию в фоновом режиме tkinter



Я новичок в программировании GUI и хочу написать программу на Python с помощью tkinter. Все, что я хочу, это запустить простую функцию в фоновом режиме, на которую можно влиять через графический интерфейс.



Функция считает от 0 до бесконечности, пока не будет нажата кнопка. По крайней мере, я этого хочу. Но я понятия не имею, как я могу запустить эту функцию в фоновом режиме, потому что mainloop() из tkinter имеет контроль все время. И если я запускаю функцию в бесконечном цикле, то mainloop() невозможно выполнить, и графический интерфейс мертв.



Я хотел бы возвращать управление обратно в mainloop () после каждого цикла, но как я могу вернуть управление из mainloop() в runapp-функцию без инициируемого пользователем события?



Вот пример кода, который убивает графический интерфейс:



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)
796   4  

4 ответов:

Вы найдете ответ в этом другом вопросе Tkinter блокирует python при загрузке значка и tk.mainloop в потоке .

Короче говоря, вам нужно иметь два потока, один для tkinter и один для фоновой задачи.

Программирование на основе событий концептуально просто. Просто представьте, что в конце вашего файла программы находится простой бесконечный цикл:

while <we have not been told to exit>:
    <pull an event off of the queue>
    <process the event>
Таким образом, все, что вам нужно сделать, чтобы постоянно выполнять какую-то небольшую задачу, - это разбить ее на кусочки размером с укус и поместить эти кусочки в очередь событий. Каждый раз, проходя через цикл, следующая итерация Вашего расчета будет выполняться автоматически.

Вы можете поместить объекты в очередь событий с помощью методаafter . Итак, создайте метод это увеличивает число,а затем переносится на несколько миллисекунд позже. Это будет выглядеть примерно так:

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

Вышеизложенное будет обновлять счетчик один раз в секунду. Когда ваша программа инициализируется, вы вызываете ее один раз, а затем после этого она вызывает себя снова и снова и т. д.

Этот метод работает только в том случае, если вы можете разбить вашу большую проблему (в вашем случае "считать вечно") на маленькие шаги ("добавить один"). Если вы делаете что-то вроде медленного запроса базы данных или огромного вычисление этот метод не обязательно будет работать.

У меня нет достаточной репутации, чтобы комментировать ответ Брайана Оукли (который я нашел очень эффективным в своей программе), поэтому я добавлю свой опыт здесь. Я обнаружил, что в зависимости от того, как долго ваша фоновая функция работает и насколько точным вы хотите, чтобы интервал времени был, может быть лучше поместить self.after вызов в начале повторяющейся функции. В Примере Брайана это выглядело бы как

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

Выполнение этого способа гарантирует, что интервал времени соблюдается. именно, отрицание любого смещения интервала, которое может произойти, если ваша функция занимает много времени.

Попробуйте понять этот пример: обновление часов в backgroud и обновление GUI (нет необходимости в 2 потоках).

# 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(  )

Кредиты: ссылка на сайт

Comments

    Ничего не найдено.