阻止方法调用n秒,显示剩余时间的消息
我正在开发简单的 GUI,但我陷入困境。这是基本流程:
- 显示文本
text
以及:- 节省
time_pressed
时间 - 启动
进度条
并更新它,直到time_notallow
到期。
- 节省
- 如果用户按
,查看time_notallow
中指定的秒数是否已经过去, 如果不是,则不允许显示下一个文本
。
基本上,我想阻止用户调用绑定到
键的方法,直到 time_notallow
通过,并显示进度条以告知他们还有多长时间等待。由于我使用 bind
,例如...
self.master.bind('<Right>', self.text_next)
...我没有 .after()
,如小部件中那样。
我尝试使用
master.after()
将bind
设置为None
并将time_notallow
设置为绑定
到self.text_next
,但它不起作用。- 创建了一个
线程
,它使用while True
循环来不断检查time_notallow
是否已通过,但应用程序崩溃了。
任何帮助表示赞赏。
编辑:一个解决方案。在 .after
中使用 lambda()
来计算秒数(感谢 Bryan Oakley)
"""
Stripped-down version to figue out time/event/threading stuff.
What this has to do:
1. Show the window and some text.
2. User presses Next arrow and new text shows. Paint the label red.
3. Prevent user form pressing again (unbind all keys), until 2 seconds passed
(time_wait).
4. Make notice of passed time and after 2 seconds bind the keys again and
paint the label green.
5. Loop the steps 2-4.
"""
import sys
import tkinter as tk
from tkinter import W, E, S, N
class Test(tk.Frame):
def __init__(self, master=None):
"""Draw the GUI"""
tk.Frame.__init__(self, master)
self.draw_widgets()
self.grid()
self.time_wait = 2
self.locked = False
self.bind_keys()
self.counter = 0
def draw_widgets(self):
"""Draw all the widgets on the frame."""
text = 'Just a sample sentence.'
#Label with the sentence
self.lbl_text = tk.Label(self, anchor="center", relief='groove')
self.lbl_text['text'] = text
self.lbl_text['font'] = ('Helvetica', 27)
self.lbl_text.grid(column=0, row=0, sticky=W+E+S+N)
self.lbl_note = tk.Label(self, anchor="center", relief='groove',
bg='green')
self.lbl_note.grid(column=0, row=1, sticky=W+E+S+N)
def text_next(self, event):
"""Get next text"""
if not self.locked:
self.counter += 1
self.lbl_text['text'] = 'The text number %s!' % self.counter
self.bind_tonone()
self.lock(self.time_wait)
def text_previous(self, event):
"""Get previous text"""
if not self.locked:
self.counter -= 1
self.lbl_text['text'] = 'The text number %s!' % self.counter
self.bind_tonone()
self.lock(self.time_wait)
def bind_keys(self):
"""Bind the keys"""
self.master.bind('<Left>', self.text_previous)
self.master.bind('<Right>', self.text_next)
self.master.bind('<Escape>', self.exit)
self.lbl_note['bg'] = 'green'
def bind_tonone(self):
"""Unbind the keys"""
self.master.bind('<Left>', None)
self.master.bind('<Right>', None)
self.master.bind('<Escape>', None)
self.lbl_note['bg'] = 'red'
def lock(self, n):
if n == 0:
self.locked = False
self.lbl_note['text'] = ''
self.lbl_note['bg'] = 'green'
else:
self.locked = True
self.lbl_note['text'] = 'Locked for %s more seconds' % n
self.lbl_note.after(1000, lambda n = n - 1: self.lock(n))
def exit(self, event):
"""Exit the program."""
sys.exit()
def start():
"""Start the gui part."""
root = tk.Tk()
app = Test(master=root)
app.mainloop()
if __name__ == '__main__':
start()
I'm working on simple GUI but I'm stuck. This is the basic flow:
- Show text
text
and:- save time in
time_pressed
- start the
progressbar
and update it untiltime_notallow
expires.
- save time in
- If a user presses
<Next>
see if seconds specified intime_notallow
have passed,
and if not, don't allow the display of the nexttext
.
Basically, I want to prevent users form calling a method bind to the <Right>
key until time_notallow
passes, and show a progressbar to inform them how long they'll have to wait. Since I use bind
, such as...
self.master.bind('<Right>', self.text_next)
...I don't have .after()
, as in widgets.
What I've tried
master.after()
to setbind
toNone
and aftertime_notallow
tobind
toself.text_next
, but it didn't work.- Created a
thread
which looped withwhile True
to check constantly iftime_notallow
is passed or not, but the application crashes.
Any help appreciated.
Edit: A Solution. Using lambda()
in .after
to count seconds (thanks to Bryan Oakley)
"""
Stripped-down version to figue out time/event/threading stuff.
What this has to do:
1. Show the window and some text.
2. User presses Next arrow and new text shows. Paint the label red.
3. Prevent user form pressing again (unbind all keys), until 2 seconds passed
(time_wait).
4. Make notice of passed time and after 2 seconds bind the keys again and
paint the label green.
5. Loop the steps 2-4.
"""
import sys
import tkinter as tk
from tkinter import W, E, S, N
class Test(tk.Frame):
def __init__(self, master=None):
"""Draw the GUI"""
tk.Frame.__init__(self, master)
self.draw_widgets()
self.grid()
self.time_wait = 2
self.locked = False
self.bind_keys()
self.counter = 0
def draw_widgets(self):
"""Draw all the widgets on the frame."""
text = 'Just a sample sentence.'
#Label with the sentence
self.lbl_text = tk.Label(self, anchor="center", relief='groove')
self.lbl_text['text'] = text
self.lbl_text['font'] = ('Helvetica', 27)
self.lbl_text.grid(column=0, row=0, sticky=W+E+S+N)
self.lbl_note = tk.Label(self, anchor="center", relief='groove',
bg='green')
self.lbl_note.grid(column=0, row=1, sticky=W+E+S+N)
def text_next(self, event):
"""Get next text"""
if not self.locked:
self.counter += 1
self.lbl_text['text'] = 'The text number %s!' % self.counter
self.bind_tonone()
self.lock(self.time_wait)
def text_previous(self, event):
"""Get previous text"""
if not self.locked:
self.counter -= 1
self.lbl_text['text'] = 'The text number %s!' % self.counter
self.bind_tonone()
self.lock(self.time_wait)
def bind_keys(self):
"""Bind the keys"""
self.master.bind('<Left>', self.text_previous)
self.master.bind('<Right>', self.text_next)
self.master.bind('<Escape>', self.exit)
self.lbl_note['bg'] = 'green'
def bind_tonone(self):
"""Unbind the keys"""
self.master.bind('<Left>', None)
self.master.bind('<Right>', None)
self.master.bind('<Escape>', None)
self.lbl_note['bg'] = 'red'
def lock(self, n):
if n == 0:
self.locked = False
self.lbl_note['text'] = ''
self.lbl_note['bg'] = 'green'
else:
self.locked = True
self.lbl_note['text'] = 'Locked for %s more seconds' % n
self.lbl_note.after(1000, lambda n = n - 1: self.lock(n))
def exit(self, event):
"""Exit the program."""
sys.exit()
def start():
"""Start the gui part."""
root = tk.Tk()
app = Test(master=root)
app.mainloop()
if __name__ == '__main__':
start()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您不需要线程或计时器来解决这个问题。您所需要的只是一个需要等待几秒钟的过程,并让它每秒调用一次自己,直到数字降至零。
它看起来像这样(在我的脑海中,未经测试):
You don't need threads or timers to solve this problem. All you need is a procedure that takes a number of seconds to wait, and have it call itself once a second until the number gets down to zero.
It would look something like this (off the top of my head, untested):
不如尝试专门设计的
来代替旋转等待线程threading.Timer
对象?How about instead of a spin-waiting thread, you try the specifically-designed
threading.Timer
object?使用计时器的快速修复方法是进行一些重构。将 self.track 最初设置为 None,然后仅将其设置为在箭头上运行/阻止。
不过,在预览中,@Bryan Oakley 有更好的解决方案。
A quick fix using your timer is to refactor a bit. Set your self.track initially to None, then only set it to run/block on arrow.
On preview though, @Bryan Oakley, has a better solution.