【问题标题】:TKinter GUI freezing with root.afterTKinter GUI 使用 root.after 冻结
【发布时间】:2018-10-11 21:24:35
【问题描述】:

我正在尝试创建代码以在输入持续时间的范围内逐步增加直流电源上的电压。我已经为此设置了一个 GUI(这是我第一次尝试制作 GUI,如果代码很奇怪,很抱歉),一切正常......除了 GUI 在代码执行时冻结,所以我无法停止环形。我已经研究了几个小时并学会了使用 root.after 而不是 time.sleep,但它似乎对 HeatLoop 功能没有帮助。 GUI 现在更新,但只是偶尔更新,当我将鼠标悬停在 GUI 上时,仍然会出现“等待光标”。有没有办法解决这个问题?

我修改了我在下面使用的代码,因此它可以在任何计算机上运行而无需编辑。

import datetime
import time
from tkinter import *

class GUIClass:


    def __init__(self, root):
        """Initialize the GUI"""

        self.root = root
        self.percent = StringVar()
        self.percent.set("00.00 %")
        self.error = StringVar()
        self.STOP = False
        self.error.set("---")
        self.currentvoltage = StringVar()
        self.currentvoltage.set("Current Voltage: 00.00 V")
        self.DT = datetime.datetime

        # Create and attach labels
        label1 = Label(root, text='Voltage')
        label2 = Label(root, text='Ramp Duration')
        label3 = Label(root, text='Percent Done: ')
        label4 = Label(root, textvariable=self.percent)
        label5 = Label(root, text="Error Message: ")
        label6 = Label(root, textvariable=self.error)
        label7 = Label(root, textvariable=self.currentvoltage)
        label1.grid(row=0, column=0, sticky=W)
        label2.grid(row=1, column=0, sticky=W)
        label3.grid(row=2, column=0, sticky=W)
        label4.grid(row=2, column=1, sticky=W)
        label5.grid(row=3, column=0, sticky=W)
        label6.grid(row=3, column=1, sticky=W)
        label7.grid(row=3, column=2, sticky=E)



        # Create and attach entries
        self.voltage = Entry(root)
        self.duration = Entry(root)
        self.voltage.grid(row=0, column=1)
        self.duration.grid(row=1, column=1)

        # Create, bind, and attach buttons
        HeatButton = Button(root, text='Heat')
        HeatButton.bind("<Button-1>", self.Heat)
        HeatButton.grid(row=0, column=2)

        CoolButton = Button(root, text='Cool')
        CoolButton.bind("<Button-1>", self.Heat)
        CoolButton.grid(row=1, column=2)

        StopButton = Button(root, text='Stop')
        StopButton.bind("<Button-1>", self.Stop)
        StopButton.grid(row=2, column=2)


    def HeatLoop(self, condition, TimeStart, TimeDuration, MaximumVoltage, Fraction=0):
        """Heat up the cell while the condition is true"""
        if condition:
            self.percent.set("{:2.2f}%".format(Fraction * 100))
            print(MaximumVoltage)
            self.currentvoltage.set("Current Voltage: {:2.2f} V".format(Fraction*MaximumVoltage))
            self.Update()
            CurrentTime = self.DT.now()
            ElapsedTime = (CurrentTime.second/3600 + CurrentTime.minute/60 + CurrentTime.hour
                           - TimeStart.second/3600 - TimeStart.minute/60 - TimeStart.hour)
            Fraction = ElapsedTime / TimeDuration
            print(Fraction)
            self.root.after(5000)
            self.HeatLoop(bool(not self.STOP and Fraction < 1),
                                          TimeStart, TimeDuration, MaximumVoltage, Fraction)


    # Define function to heat up cell
    def Heat(self, event):
        # Initialize Parameters
        self.STOP = False
        self.error.set("---")
        self.Update()



        # Try to get voltage and duration from the GUI
        MaxVoltage = self.voltage.get()
        TimeDuration = self.duration.get()
        try:
            MaxVoltage = float(MaxVoltage)
            try:
                TimeDuration = float(TimeDuration)
            except:
                self.error.set("Please enter a valid time duration")
                self.Update()
                self.STOP = True
        except:
            self.error.set("Please enter a valid voltage value")
            self.Update()
            self.STOP = True

        TimeStart = self.DT.now()

        self.HeatLoop(True,
                      TimeStart, TimeDuration, MaxVoltage)


    def Stop(self, event):
        self.STOP = True
        print("turned off voltage")

    def Update(self):
        self.root.update_idletasks()
        self.root.update()


root1 = Tk()
a = GUIClass(root1)
root1.mainloop()

【问题讨论】:

    标签: python python-3.x loops tkinter


    【解决方案1】:

    root.after(5000)time.sleep(5) 没有什么不同。它正在做你告诉它的事情:冻结五秒钟。

    如果你想每五秒运行一次self.HeatLoop,方法是这样的:

    self.root.after(5000, self.HeatLoop, 
                    bool(not self.STOP and Fraction < 1),
                    TimeStart, TimeDuration, MaximumVoltage, 
                    Fraction)
    

    当您向after 提供两个或更多参数时,tkinter 会将该函数添加到队列中,并在时间到期后调用该函数。这允许事件循环在五秒的时间间隔内继续处理事件。

    一个稍微好一点的编写方法是检查函数内部的条件而不是传递条件,以便在执行工作之前立即评估条件,而不是在执行工作前五秒。

    例如:

    def HeatLoop(self, TimeStart, TimeDuration, MaximumVoltage, Fraction=0):
        if self.STOP and Fraction < 0:
            return
        ...
        self.root.after(5000, self.HeatLoop, 
                        TimeStart, TimeDuration, MaximumVoltage, 
                        Fraction)
    

    【讨论】:

    • 哦,谢谢!我尝试了类似的方法,但我使用了错误的语法 ... self.root.after(5000, self.HeatLoop(params)) =/= self.root.after(5000, self.HeatLoop, params)。
    猜你喜欢
    • 2015-04-08
    • 2018-05-03
    • 2015-11-11
    • 1970-01-01
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    • 2013-11-02
    • 2021-05-03
    相关资源
    最近更新 更多