Зависание графического интерфейса TKinter с root.after

Я пытаюсь создать код для постепенного увеличения напряжения на источнике питания постоянного тока в течение продолжительности ввода. Я настроил для этого графический интерфейс (это моя первая попытка создать графический интерфейс, извините, если код странный), и все работает ... за исключением того, что графический интерфейс зависает во время выполнения кода, поэтому я не могу остановить петля. Я изучал это несколько часов и научился использовать root.after вместо time.sleep, но, похоже, это не помогло в функции HeatLoop. Графический интерфейс обновляется сейчас, но только время от времени, и при наведении курсора на графический интерфейс все еще появляется «курсор ожидания». Есть ли способ исправить это?

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

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 есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
252
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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).

Matthew 01.05.2018 22:40

Другие вопросы по теме