我有这个程序每秒都会发出哔哔声,直到它停止。问题是我按下"开始"并且哔哔声开始,我无法点击"停止"按钮,因为窗口冻结。欢迎任何帮助。
#!/usr/bin/python
import Tkinter, tkMessageBox, time, winsound, msvcrt
running = True
Freq = 2500
Dur = 150
top = Tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200
def start():
sec = 0
while running:
if sec % 1 == 0:
winsound.Beep(Freq, Dur)
time.sleep(1)
sec += 1
def stop():
running = False
startButton = Tkinter.Button(top, height=2, width=20, text ="Start", command = start)
stopButton = Tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
top.mainloop()
答案 0 :(得分:6)
您的代码有几个问题。首先,您不应在Tkinter程序中使用time.sleep()
,因为它会干扰mainloop()
。相反,通常使用通用窗口小部件方法.after()
来安排函数在指定的延迟之后运行。
其次,您没有正确使用全局变量。当您为函数中的命名变量赋值时,它将创建一个局部变量,除非该名称先前已声明为global
。因此,例如,您的stop()
函数正在创建名为running
的局部变量,并将其值设置为0,不更改具有相同名称的全局变量的值。< / p>
之前的规则并不适用于仅引用(读取)变量的当前值。这就是为什么没有在Freq
中声明Dur
和start()
全局变量的原因。
另一个问题是sec % 1 == 0
函数中的start()
。任何值% 1
都是0
。要检查奇数/均匀度,请使用sec % 2
。
这是一个可以重新格式化的工作版本,可以更紧密地关注PEP 8 - Style Guide for Python Code。
import Tkinter
import tkMessageBox
import time
import winsound
FREQ = 2500
DUR = 150
after_id = None
secs = 0
def beeper():
global after_id
global secs
secs += 1
if secs % 2 == 0: # every other second
winsound.Beep(FREQ, DUR)
after_id = top.after(1000, beeper) # check again in 1 second
def start():
global secs
secs = 0
beeper() # start repeated checking
def stop():
global after_id
if after_id:
top.after_cancel(after_id)
after_id = None
top = Tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100')
startButton = Tkinter.Button(top, height=2, width=20, text="Start",
command=start)
stopButton = Tkinter.Button(top, height=2, width=20, text="Stop",
command=stop)
startButton.pack()
stopButton.pack()
top.mainloop()
答案 1 :(得分:2)
您的代码有top.mainloop()
,其中有while
个循环在其中运行,除此之外,您还在def start():
内部有一个while循环。所以它就像循环内循环。
您可以创建一个功能,为循环体执行您想要的操作。它应该完成循环的一次迭代。一旦完成,它需要安排自己在将来某个时间使用after
再次调用。未来多远将定义循环的运行速度。
然后您可以使用after_cancel
取消该活动。下面的代码为我工作
import Tkinter, tkMessageBox, time, winsound, msvcrt
Freq = 2500
Dur = 150
top = tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200
def start():
global job1
if running == True:
winsound.Beep(Freq, Dur)
job1 = top.after(1000, start) # reschedule event in 1 seconds
def stop():
global job1
top.after_cancel(job1)
startButton = tkinter.Button(top, height=2, width=20, text ="Start", command = start)
stopButton = tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
#top.after(1000, start)
top.mainloop()
答案 2 :(得分:1)
问题是start()
中的while循环阻止了GUI处理程序mainloop()
。尝试在Tk.after()
中使用start()
:
def start(force=True):
global running
if force:
running = True
if running:
winsound.Beep(Freq, Dur)
top.after(1000, start, False)
并更改stop()
:
def stop():
global running
running = False
答案 3 :(得分:1)
再次击败拳击,但这里什么都没有。如上所述,使用after
功能来阻止mainloop
阻止
看到:
tkinter: how to use after method
#!/usr/bin/python
import Tkinter, tkMessageBox, time
Freq = 2500
Dur = 150
top = Tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200
def start():
print ("Beep")
top.after(1000, start)
def stop():
print ("Stop")
top.quit()
startButton = Tkinter.Button(top, height=2, width=20, text ="Start", command = start)
stopButton = Tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
top.mainloop()
答案 4 :(得分:0)
我使用了线程和全局变量来满足您的需求。如果您了解它们的工作原理,则不必那么复杂。只需添加几行,然后对现有行进行少量更改,即可正常工作。浏览以查看对原始代码所做的更改。
#!/usr/bin/python
import tkinter
from tkinter import messagebox
import time, winsound, msvcrt
from threading import Thread
running = True
Freq = 2500
Dur = 150
top = tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200
def button_click():
global running #create global
running = True
# Create new thread
t = Thread(target = start)
# Start new thread
t.start()
def start():
sec = 0
while running:
if running == False:
break
if sec % 1 == 0:
winsound.Beep(Freq, Dur)
time.sleep(1)
sec += 1
def stop():
global running #create global
running = False
startButton = tkinter.Button(top, height=2, width=20, text ="Start", command = button_click) #Change to call button_click instead start
stopButton = tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
top.mainloop()