Как постоянно обновлять ярлык tkinter до нажатия кнопки? - PullRequest
1 голос
/ 02 июля 2019

Я пытаюсь создать простое приложение таймера, в котором пользователь нажимает кнопку запуска (или использует привязку клавиш), и часы непрерывно обновляются, пока пользователь не нажимает кнопку остановки (или не использует привязку клавиш), но при попыткесоздать это Я застрял в бесконечном цикле.

Я попытался создать логический флаг, в котором True указывает на завершение обновления, и использовал цикл while для проверки этого, однако программа в конечном итоге застряла вбесконечный цикл.Это все в Python 3.x (в частности, v3.6.7).В предоставленном коде я сократил его настолько, насколько смог, сохранив ошибку и контекст ошибки.Я также удалил привязки клавиш, о которых упоминал ранее, поскольку они не являются частью проблемы.

import tkinter as tk
class cubeTimer():
    def __init__(self):
        ##Defines parts of timer
        self.start_time = 0.0
        self.end_time = 0.0
        self.difference = 0.0
    def get_time(self,num):
        ##Gets time since epoch
        if num == 1:
            self.start_time = time.time()
        elif num == 2:
            self.end_time = time.time()
    def get_difference(self):
        ##Finds difference bwteen start and end times
        self.difference = self.end_time - self.start_time
        return self.difference
class cubeGUI():
    def __init__(self):
        ##Instance variables for later use
        self.num = 0
        self.time_difference = 0
        self.flag = False
        ##Creates instance of timer class
        self.timer = cubeTimer()
        ##Creates GUI
        self.root = tk.Tk()
        ##Label to show the solve time
        self.time_label = tk.Label(text='-',height=5,width=10)
        self.time_label.grid(row=1,columnspan=2,sticky=tk.W)
        ##Button to start timer
        self.start_button = tk.Button(text='Start',height=5,width=10,command=self.start_process)
        self.start_button.grid(row=2,column=0)
        ##Button to end timer, initialised as disabled
        self.end_button = tk.Button(text='End',state=tk.DISABLED,height=5,width=10,command=self.end_process)
        self.end_button.grid(row=2,column=1)
    def start_process(self):
        ##Sets variable
        self.num = 1
        ##Calls timer to get time
        self.timer.get_time(self.num)
        ##Configures necessary buttons
        self.start_button.configure(state=tk.DISABLED)
        self.end_button.configure(state=tk.NORMAL)
        while self.flag == False:
            self.time_difference = self.timer.get_difference()
            self.time_label.configure(text=self.time_difference)
            time.sleep(0.1)
    def end_process(self):
        ##Sets variable
        self.num = 2
        ##Calls timer to get time
        self.timer.get_time(self.num)
        ##Updates flag
        self.flag = True
        ##Configures necessary button
        self.end_button.configure(state=tk.DISABLED)
        ##Calls time difference
        self.time_difference = self.timer.get_difference()
        ##Puts it on screen
        self.time_label.configure(text=self.time_difference)
myTimer = cubeGUI()

Я ожидал, что программа будет обновлять метку времени каждые 0,1 секунды (или любой заданный период времени), но вместо этого программазависает, когда сталкивается с бесконечным циклом и застревает.

1 Ответ

1 голос
/ 02 июля 2019

Вы не можете использовать цикл внутри GUI, потому что он мешает основной петле GUI. Вместо этого вы должны структурировать свою программу для интеграции в основной цикл. В tkinter это делается методом after(). Вот ваш исправленный код (насколько я могу понять, что вы пытаетесь сделать), включая соответствующий класс:

import tkinter as tk

class CubeTimer(tk.Frame):
    def __init__(self, master=None, **kwargs):
        super().__init__(master, **kwargs)

        self.timer = ' '
        self.time_value = tk.IntVar()

        ##Label to show the solve time
        time_label = tk.Label(self, textvariable=self.time_value,height=5,width=10)
        time_label.grid(row=1,columnspan=2,sticky=tk.W)
        ##Button to start timer
        self.start_button = tk.Button(self, text='Start',height=5,width=10,command=self.start_process)
        self.start_button.grid(row=2,column=0)
        ##Button to end timer, initialised as disabled
        self.end_button = tk.Button(self, text='End',state=tk.DISABLED,height=5,width=10,command=self.end_process)
        self.end_button.grid(row=2,column=1)

    def timer_tick(self):
        self.time_value.set(self.time_value.get() + 1)
        self.timer = self.after(1000, self.timer_tick) # schedule this method to be called again in 1,000 millisconds (1 second)

    def start_process(self):
        ##Configures necessary buttons
        self.start_button.configure(state=tk.DISABLED)
        self.end_button.configure(state=tk.NORMAL)
        self.timer_tick()

    def end_process(self):
        self.after_cancel(self.timer) # cancel the scheduled method call

        ##Configures necessary button
        self.end_button.configure(state=tk.DISABLED)
        self.start_button.configure(state=tk.NORMAL)

def main():
    root = tk.Tk()
    myTimer = CubeTimer(root)
    myTimer.pack()
    root.mainloop()

if __name__ == "__main__":
    main()
...