简体   繁体   English

如何使用 tkinter 更新多个标签

[英]How to update multiple labels with tkinter

I am trying to make a stopwatch in python that also shows the elapsed time in decimal hours as worktime , and also converts whatever time elapsed over 8 hrs into overtime .我正在尝试在 python 中制作一个worktime ,它还以十进制小时数显示经过的时间作为工作时间,并将超过 8 小时的任何时间转换为overtime

I got the stopwatch part functional (to be fair I mostly mimicked tutorials), but when I tried to add the additional decimal, then things got wrong.我得到了秒表部分功能(公平地说,我主要模仿教程),但是当我尝试添加额外的小数时,事情就出错了。 I tried a bunch of stuff that somewhat looked logical but got either more errors at runtime, or my labels aside the stopwatch stayed at zero, or in the present case python crashes after a few seconds (my guess is that the three .after are basically calling running update() exponentially?)我尝试了一堆看起来有点合乎逻辑的东西,但在运行时出现了更多错误,或者我的秒表旁边的标签保持为零,或者在目前的情况下,python 在几秒钟后崩溃(我的猜测是这三个.after基本上是以指数方式调用运行update() ?)

I suppose the bulldozer solution would be for me to just make duplicates of the update() function for each of my labels, I'm 9/10 sure it will work, but that just sounds stupidly redundant.我想推土机解决方案对我来说只是为我的每个标签复制update()函数,我 9/10 肯定它会起作用,但这听起来很愚蠢。

import tkinter as tk

### Vars
counting = False
hours, minutes, seconds = 0, 0, 0
totalWorktime, overtime = 0, 0

### Funcs

def start():
    global counting
    if not counting:
        update()
        counting = True

def pause():
    global counting
    if counting:
        stopwatch_label.after_cancel(update_time)
        worktime_label.after_cancel(update_worktime)
        overtime_label.after_cancel(update_overtime)
        counting = False

def reset():
    global counting
    if counting:
        stopwatch_label.after_cancel(update_time)
        worktime_label.after_cancel(update_worktime)
        overtime_label.after_cancel(update_overtime)
        counting = False
    global hours, minutes, seconds, totalWorktime, overtime
    hours, minutes, seconds = 0, 0, 0
    totalWorktime, overtime = 0, 0
    stopwatch_label.config(text='00:00:00')

# update stopwatch label
def update():
    global hours, minutes, seconds, totalWorktime, overtime
    # time counting system
    seconds += 1
    if seconds ==60:
        minutes += 1
        seconds = 0
    if minutes == 60:
        hours += 1
        minutes = 0
    totalWorktime = hours + (minutes / 60)
    if totalWorktime > 8:
        overtime = totalWorktime - 8
    # format with zero padding
    hours_string = f'{hours}' if hours > 9 else f'0{hours}'
    minutes_string = f'{minutes}' if minutes > 9 else f'0{minutes}'
    seconds_string = f'{seconds}' if seconds > 9 else f'0{seconds}'
    # building label
    stopwatch_label.config(text=hours_string + ':' + minutes_string + ':' + seconds_string)
    global update_time, update_worktime, update_overtime
    update_time = stopwatch_label.after(10, update)
    update_worktime = worktime_label.after(10, update)
    update_overtime = overtime_label.after(10, update)

### UI
# main window
root = tk.Tk()
root.geometry('512x256')
root.title('Worktime Stopwatch')

# time display
stopwatch_label = tk.Label(text='00:00:00', font=('Arial', 80))
stopwatch_label.pack()
worktime_label = tk.Label(text='Work time : ' + str(totalWorktime), font=('Arial', 20))
worktime_label.pack()
overtime_label = tk.Label(text='Overtime : ' + str(overtime), font=('Arial', 20))
overtime_label.pack()

# buttons
start_button = tk.Button(text='Start', height=4, width=8, font=('Arial', 20), command=start)
start_button.pack(side=tk.LEFT)
pause_button = tk.Button(text='Pause', height=4, width=8, font=('Arial', 20), command=pause)
pause_button.pack(side=tk.LEFT)
reset_button = tk.Button(text='Reset', height=4, width=8, font=('Arial', 20), command=reset)
reset_button.pack(side=tk.LEFT)

# run
root.mainloop()

PS: Yes I know I could have used the time module, I just like simple funny math in my scripts. PS:是的,我知道我可以使用时间模块,我只是喜欢脚本中简单有趣的数学。
PS2: Yes I know my current stopwatch counts time 100 times too fast, that's to make it easy to test. PS2:是的,我知道我现在的秒表计数时间太快了 100 倍,这是为了便于测试。 I will get back to 1000ms when it works.当它工作时,我会回到 1000 毫秒。

Thanks to @acw1668's point out, I looked again at my code with a fresh mind and noticed how I misunderstood the usage of .after() and was expecting it was responsible for refreshing the labels, while all it really does is calling update() at a fixed interval.感谢@acw1668 的指出,我重新审视了我的代码,并注意到我是如何误解了.after()的用法并期望它负责刷新标签,而它真正所做的只是调用update()以固定的间隔。

The important part was just two lines above, under my "building label" comment:重要的部分只是上面两行,在我的“建筑标签”评论下:

stopwatch_label.config(text=hours_string + ':' + minutes_string + ':' + seconds_string)

For some reason, my brain though this just combined the different parts of the stopwatch label into one.出于某种原因,我的大脑虽然只是将秒表标签的不同部分合二为一。 But the core usage of .config() is precisely to change the text.但是.config()的核心用途恰恰是改变文本。

So all i had to do was to duplicate this line twice, and change it to impact my worktime and overtime counters:所以我所要做的就是把这条线复制两次,然后改变它来影响我的工作overtime worktime

worktime_label.config(text='Work time : ' + str(totalWorktime))
overtime_label.config(text='  Overtime : ' + str(overtime))

I also had to remove their respective .after_cancel() methods in reset() and pause() , and after some more cosmetic changes, here's the whole functional code:我还必须在reset()pause()中删除它们各自的.after_cancel()方法,并且在进行了一些更美观的更改之后,这是整个功能代码:

import tkinter as tk

### Vars
counting = False
hours, minutes, seconds = 0, 0, 0
totalWorktime, overtime = 0, 0

### Funcs

def start():
    global counting
    if not counting:
        update()
        counting = True

def pause():
    global counting
    if counting:
        stopwatch_label.after_cancel(update_time)
        counting = False

def reset():
    global counting
    if counting:
        stopwatch_label.after_cancel(update_time)
        counting = False
    global hours, minutes, seconds, totalWorktime, overtime
    hours, minutes, seconds = 0, 0, 0
    totalWorktime, overtime = 0, 0
    stopwatch_label.config(text='00:00:00')
    worktime_label.config(text='Work time : 0')
    overtime_label.config(text='  Overtime : 0')

# update stopwatch label
def update():
    global hours, minutes, seconds, totalWorktime, overtime
    # time counting system
    seconds += 1
    if seconds ==60:
        minutes += 1
        seconds = 0
    if minutes == 60:
        hours += 1
        minutes = 0
    totalWorktime = round(hours + (minutes / 60), 2)
    if totalWorktime > 8:
        overtime = totalWorktime - 8
    # format with zero padding
    hours_string = f'{hours}' if hours > 9 else f'0{hours}'
    minutes_string = f'{minutes}' if minutes > 9 else f'0{minutes}'
    seconds_string = f'{seconds}' if seconds > 9 else f'0{seconds}'
    # refresh labels with new text content
    stopwatch_label.config(text=hours_string + ':' + minutes_string + ':' + seconds_string)
    worktime_label.config(text='Work time : ' + str(totalWorktime))
    overtime_label.config(text='  Overtime : ' + str(overtime))
    global update_time, update_worktime, update_overtime
    update_time = stopwatch_label.after(1000, update)

### UI
# main window
root = tk.Tk()
root.geometry('512x256')
root.title('Worktime Stopwatch')

# time display
stopwatch_label = tk.Label(text='00:00:00', font=('Arial', 80))
stopwatch_label.pack()
worktime_label = tk.Label(text='Work time : 0', font=('Arial', 20), anchor="w", width=20)
worktime_label.pack()
overtime_label = tk.Label(text='  Overtime : 0', font=('Arial', 20), anchor="w", width=20)
overtime_label.pack()

# buttons
start_button = tk.Button(text='Start', height=4, width=8, font=('Arial', 20), command=start)
start_button.pack(side=tk.LEFT)
pause_button = tk.Button(text='Pause', height=4, width=8, font=('Arial', 20), command=pause)
pause_button.pack(side=tk.LEFT)
reset_button = tk.Button(text='Reset', height=4, width=8, font=('Arial', 20), command=reset)
reset_button.pack(side=tk.LEFT)

# run
root.mainloop()

Thanks for the help!谢谢您的帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM