【问题标题】:Alternative for while loops in tkintertkinter 中 while 循环的替代方案
【发布时间】:2019-11-12 09:45:46
【问题描述】:

我正在尝试制作一个闹钟应用程序:闹钟应该在预设的时间响起。如果没有 tkinter,我的代码完全可以正常工作,但是使用 tkinter 它根本不起作用。 在原始代码中有一个 while 循环,我注意到并读到它不能与 tkinter 结合使用。我决定摆脱循环,但现在当我输入时间时警报会立即响起。

我已经阅读了有关使用 r.after(time_ms, function()) 的信息。但我不知道如何在我的代码中正确实现它。我读过它必须在函数的末尾和 r.mainloop() 之前,但我无法让它工作。有人能帮帮我吗?非常感谢你! 我已经阅读了很多关于此的或 stackoverflow 帖子,但我没有足够的经验来让它与这些答案一起工作。 :(

import tkinter as tk
from datetime import datetime, date
import time
from pygame import mixer

r = tk.Tk()
r.title('Smart Watch')

def alarm_sound():
    mixer.init()
    mixer.music.load('Wecker-sound.mp3')

def end():
    mixer.init()
    mixer.music.stop()

def display_output():
    hour = entry_hour.get()
    int_hour = int(hour)
    minute = entry_minute.get()
    int_minute = int(minute)
    second = entry_second.get()
    int_second = int(second)
    confirmation_message = ('Alarm has been set for ' + hour + ':' +
                             minute + ':' + second + '.')
    text_label['text'] = confirmation_message


    if (time.localtime().tm_hour == hour and
            time.localtime().tm_min == entry_minute.get() and
                time.localtime().tm_sec == entry_second.get()):
        alarm_sound()
        mixer.music.play()

message = tk.Label(r, text='What is the alarm message you\'d like to receive when the alarm goes off?',
                  font=('Roboto-regular', 12), fg='black')
message.pack()
entry_message = tk.Entry(r, width=45)
entry_message.pack()
enter_hour = tk.Label(r, text='Enter the hour for the alarm to go off: ',
                        font=('Roboto-regular', 12), fg='black')
enter_hour.pack()
entry_hour = tk.Entry(r, width=10)
entry_hour.pack()
enter_minute = tk.Label(r, text='Enter the minute for the alarm to go off: ',
                        font=('Roboto-regular', 12), fg='black')
enter_minute.pack()
entry_minute = tk.Entry(r, width=10)
entry_minute.pack()
enter_second = tk.Label(r, text='Enter the second for the alarm to go off: ',
                    font=('Roboto-regular', 12), fg='black')
enter_second.pack()
entry_second = tk.Entry(r, width=10)
entry_second.pack()
text_label = tk.Label(r, font=('Roboto-regular', 12, 'bold'),
                      fg='tomato')
text_label.pack()
submit_button = tk.Button(r, text='Submit',
                          fg='black', width=30, height=2, relief='groove',
                          cursor='hand2', command=display_output)
submit_button.pack()
snooze_button = tk.Button(r, text='Snooze alarm',
                          fg='black',
                          width=30, height=2, relief='groove',
                          cursor='hand2', command=end)
snooze_button.pack()


r.mainloop()

# The original code without tkinter has the while loop like this:
while True:
    if time.localtime().tm_hour == hr and time.localtime().tm_min == mn and time.localtime().tm_sec == sc:
        print(message)
        break
alarm_Sound()
mixer.music.play()

【问题讨论】:

  • 使用after 更改时钟时间的示例:furas/tkitner/clock-function 它不使用while True,但它使用update_time 中的after 再次运行update_time 所以它可以工作像循环。
  • 顺便说一句:after(...) 作为第二个参数需要没有()的函数名称
  • 谢谢。我试过不带 () 的函数名称,但随后我收到一条错误消息,提示“参数错误:必须是取消、空闲、信息或整数”。
  • 总是将完整的错误消息(从单词“Traceback”开始)作为文本(不是屏幕截图)放在有问题的(不是评论)中。还有其他有用的信息。

标签: python loops tkinter while-loop


【解决方案1】:

首先,您应该使用全局变量来保留来自Entry 的值,然后在检查时间的函数中使用它们。此函数应在没有时间报警时使用after 再次运行。它还应该跳过after() 以停止检查时间。

def display_output():
    global int_hour
    global int_minute
    global int_second

    hour = entry_hour.get()
    int_hour = int(hour)

    minute = entry_minute.get()
    int_minute = int(minute)

    second = entry_second.get()
    int_second = int(second)

    text_label['text'] = 'Alarm has been set for {}:{}:{}.'.format(hour, minute, second)
    # start checking time    
    check_time()


def check_time():

    dt = time.localtime()

    if (dt.tm_hour == int_hour and dt.tm_min == int_minute and dt.tm_sec == int_second):
        alarm_sound()
        mixer.music.play()
    else:
        r.after(1000, check_time) # check it again after 1000ms but only if it doesn't play sound

代码需要其他全局变量来控制警报是否在您停止和尝试再次设置时运行。


import time
from datetime import datetime, date
import tkinter as tk
from pygame import mixer

# --- functions ---

def alarm_sound():
    global running_alarm

    running_alarm = True

    mixer.music.load('Wecker-sound.mp3')

def end():
    global running_alarm

    if running_alarm:
        running_alarm = False
        mixer.music.stop()
        text_label['text'] = ''

def display_output():
    global int_hour
    global int_minute
    global int_second

    hour = entry_hour.get()
    int_hour = int(hour)

    minute = entry_minute.get()
    int_minute = int(minute)

    second = entry_second.get()
    int_second = int(second)

    confirmation_message = ('Alarm has been set for {}:{}:{}.'.format(hour, minute, second))

    text_label['text'] = confirmation_message

    check_time()


def check_time():

    dt = time.localtime()

    if (dt.tm_hour == int_hour and dt.tm_min == int_minute and dt.tm_sec == int_second):
        checking_time = False # stop l
        alarm_sound()
        mixer.music.play()
    else:
        r.after(1000, check_time)

# --- main ---

running_alarm = False # default value at start

mixer.init()


r = tk.Tk()
r.title('Smart Watch')

message = tk.Label(r, text='What is the alarm message you\'d like to receive when the alarm goes off?',
                  font=('Roboto-regular', 12), fg='black')
message.pack()

entry_message = tk.Entry(r, width=45)
entry_message.pack()

enter_hour = tk.Label(r, text='Enter the hour for the alarm to go off: ',
                        font=('Roboto-regular', 12), fg='black')
enter_hour.pack()

entry_hour = tk.Entry(r, width=10)
entry_hour.pack()

enter_minute = tk.Label(r, text='Enter the minute for the alarm to go off: ',
                        font=('Roboto-regular', 12), fg='black')
enter_minute.pack()

entry_minute = tk.Entry(r, width=10)
entry_minute.pack()

enter_second = tk.Label(r, text='Enter the second for the alarm to go off: ',
                    font=('Roboto-regular', 12), fg='black')
enter_second.pack()

entry_second = tk.Entry(r, width=10)
entry_second.pack()

text_label = tk.Label(r, font=('Roboto-regular', 12, 'bold'),  fg='tomato')
text_label.pack()

submit_button = tk.Button(r, text='Submit',
                          fg='black', width=30, height=2, relief='groove',
                          cursor='hand2', command=display_output)
submit_button.pack()

snooze_button = tk.Button(r, text='Snooze alarm',
                          fg='black',
                          width=30, height=2, relief='groove',
                          cursor='hand2', command=end)
snooze_button.pack()

r.mainloop()

【讨论】:

  • 当我在答案中运行代码时,我可以看到提交按钮 - 所以我不知道你有什么问题。你有没有运行它 console/terminal/cmd.exe 来看看你是否收到任何错误消息?
  • 感谢您的回复。这对我有帮助。编辑:我没有看到该按钮,但我自己添加了它,现在它可以正常工作了。谢谢!
【解决方案2】:

代替while True: 循环,使用一个函数并在每个“指定间隔”时间为该函数注册一个回调。这是在下面的代码中完成的:

def wait_for_alarm():
    after = r.after(1000, wait_for_alarm)  # 1000 refers to 1 second
    if time.localtime().tm_hour == hr and time.localtime().tm_min == mn and time.localtime().tm_sec == sc:
        print(message)
        alarm_Sound()
        mixer.music.play()

【讨论】:

  • 感谢您的回复!但是 Python 给出了一个 SyntaxError: break outside loop。
  • 哦,是的,你不再需要休息了。 @BoAnonymous 已编辑以纠正该问题,谢谢
  • 没问题,非常感谢您的快速回复。我现在要玩这个代码。
猜你喜欢
  • 1970-01-01
  • 2019-02-15
  • 2013-08-23
  • 2017-08-06
  • 2011-06-30
  • 1970-01-01
  • 1970-01-01
  • 2020-03-21
  • 1970-01-01
相关资源
最近更新 更多