在Python3中如何在编译器睡眠时消磨时间.sleep()
我想在按下停止按钮后立即退出循环。但有了这段代码,我只能在执行当前迭代和下一次迭代之后才能出来 这对我的应用非常重要,因为我将使用它来自动化仪器,在按下停止按钮后操作必须立即停止在Python3中如何在编译器睡眠时消磨时间.sleep(),python,tkinter,Python,Tkinter,我想在按下停止按钮后立即退出循环。但有了这段代码,我只能在执行当前迭代和下一次迭代之后才能出来 这对我的应用非常重要,因为我将使用它来自动化仪器,在按下停止按钮后操作必须立即停止 # -*- coding: utf-8 -*- """ Created on Sun Jun 17 17:01:12 2018 @author: Lachu """ import time from tkinter import * from tkinter import ttk root=Tk() def s
# -*- coding: utf-8 -*-
"""
Created on Sun Jun 17 17:01:12 2018
@author: Lachu
"""
import time
from tkinter import *
from tkinter import ttk
root=Tk()
def start():
global stop_button_state
for i in range(1,20):
if (stop_button_state==True):
break
else:
print('Iteration started')
print('Iteration number: ', i)
root.update()
time.sleep(10)
print('Iteration completed \n')
def stop_fun():
global stop_button_state
stop_button_state=True
start=ttk.Button(root, text="Start", command=start).grid(row=0,column=0,padx=10,pady=10)
p=ttk.Button(root, text="Stop", command=stop_fun).grid(row=1,column=0)
stop_button_state=False
root.mainloop()
如果不使用单独的线程,您可以始终迭代sleep命令,这将使代码更具响应性。
e、 g.这会将单击停止和循环退出之间的等待时间减少到十分之一秒,同时在循环之间保留10秒的间隔
# -*- coding: utf-8 -*-
"""
Created on Sun Jun 17 17:01:12 2018
@author: Lachu
"""
import time
from tkinter import *
from tkinter import ttk
root=Tk()
stop_button_state=False
def start():
global stop_button_state
for i in range(1,20):
if (stop_button_state==True):
break
print('Iteration started')
print('Iteration number: ', i)
for i in range(100):
root.update()
time.sleep(0.1)
if (stop_button_state==True):
break
print('Iteration completed \n')
def stop_fun():
global stop_button_state
stop_button_state=True
ttk.Button(root, text="Start", command=start).grid(row=0,column=0,padx=10,pady=10)
ttk.Button(root, text="Stop", command=stop_fun).grid(row=1,column=0)
root.mainloop()
在GUI程序中使用
time.sleep
通常不是一个好主意,因为它会使所有内容都处于睡眠状态,因此GUI无法自我更新或响应事件。此外,当你想中断睡眠时,它会变得混乱
我已将您的代码改编为使用模块中的计时器。我们可以很容易地立即中断这个计时器
,而且它不会阻塞GUI
为了实现这一点,我将
循环的计数移动到一个生成器中
如果您在计数过程中按下开始按钮,它将告诉您已经在计数。当一个计数周期结束时,无论是按停止键,还是按到数字的末尾,您都可以再次按开始键开始新的计数
import tkinter as tk
from tkinter import ttk
from threading import Timer
root = tk.Tk()
delay = 2.0
my_timer = None
# Count up to `hi`, one number at a time
def counter_gen(hi):
for i in range(1, hi):
print('Iteration started')
print('Iteration number: ', i)
yield
print('Iteration completed\n')
# Sleep loop using a threading Timer
# The next `counter` step is performed, then we sleep for `delay`
# When we wake up, we call `sleeper` to repeat the cycle
def sleeper(counter):
global my_timer
try:
next(counter)
except StopIteration:
print('Finished\n')
my_timer = None
return
my_timer = Timer(delay, sleeper, (counter,))
my_timer.start()
def start_fun():
if my_timer is None:
counter = counter_gen(10)
sleeper(counter)
else:
print('Already counting')
def stop_fun():
global my_timer
if my_timer is not None:
my_timer.cancel()
print('Stopped\n')
my_timer = None
ttk.Button(root, text="Start", command=start_fun).grid(row=0, column=0, padx=10, pady=10)
ttk.Button(root, text="Stop", command=stop_fun).grid(row=1,column=0)
root.mainloop()
您最好使用根目录。在之后,使用线程:
正如其他人指出的,在任何情况下,在GUI中使用time.sleep
都是一个坏主意
您也不应该将按钮命名为与功能相同的名称
这里也不需要调用root.update
from tkinter import *
from tkinter import ttk
def start_process(n=0, times=10):
n += 1
if not stop_button_state and n < times:
print('Iteration started')
print(f'Iteration number: {n}')
print('Iteration completed \n')
root.after(1000, start_process, n)
else:
print('stopping everything')
def stop_fun():
global stop_button_state
stop_button_state = True
if __name__ == '__main__':
root = Tk()
start = ttk.Button(root, text="Start", command=start_process)
start.grid(row=0, column=0, padx=10, pady=10)
p = ttk.Button(root, text="Stop", command=stop_fun)
p.grid(row=1, column=0)
stop_button_state = False
root.mainloop()
从tkinter导入*
从tkinter导入ttk
def启动_过程(n=0,次数=10):
n+=1
如果不停止按钮状态,则n<次:
打印('迭代已开始')
打印(f'迭代编号:{n}')
打印('迭代已完成\n')
root.after(1000,启动\u进程,n)
其他:
打印('停止一切')
def stop_fun():
全局停止按钮状态
停止按钮状态=真
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
root=Tk()
start=ttk.按钮(root,text=“start”,command=start\u进程)
网格(行=0,列=0,padx=10,pady=10)
p=ttk.按钮(root,text=“Stop”,command=Stop\u fun)
p、 网格(行=1,列=0)
停止按钮状态=错误
root.mainloop()
您必须使用thread.grid
方法返回None
,因此使用start=ttk.Button(root,text=“start”,command=start).grid(row=0,column=0,padx=10,pady=10)
可以将start
设置为None
。您不应该尝试使用start
作为按钮名称和函数名称。这里并没有什么坏处,因为在将函数名传递给按钮构造函数之后,您永远不需要函数名。OTOH,为什么还要麻烦命名按钮,你在任何地方都不使用这个名称?在这段代码中,当Start
函数运行时,你可以再次按下Start按钮,这样可以同时发生多个迭代。这是有意的吗?研究tkinterafter
方法,它可以让您计划函数在将来运行或按间隔运行。您不应该在GUI程序中使用sleep
,因为它完全按照它所说的那样:它会使整个程序进入睡眠状态。@BryanOakley我想我应该在之后使用,但我认为使用线程处理可能会很有趣。)您不应该在GUI线程中调用sleep
,因为tkinter无法在程序睡眠时处理任何事件。@BryanOakley鉴于OP提出了一个专门使用睡眠的问题,我选择提供一个适合该问题的答案。我不使用tkinter,但我认为root.update()
会立即将控制权返回主循环。我可能已经在这个网站上发布了100个答案,说明如何在之后使用,我在这里可能写不出任何比我的其他答案更好的东西。@BryanOakley那么,发布一个适当的链接到其中一个怎么样?是的,这比我的版本简单一点。但是你用n+=1
而不是发电机来“作弊”:DSweet。有一点很好,Python3.6中只引入了前缀为“f”的格式化字符串文字。它满足了一半的要求。它不会立即退出循环。它仅在执行当前迭代之后出现。是否可以通过稍微更改代码立即显示出来?是的,您需要为关键字参数times
提供一个值,以达到此目的。请解释“my_timer=timer(delay,sleeper,(counter,)”在这里是如何工作的。@maheshchaluvadi它创建一个计时器,该计时器睡眠delay
秒,然后调用sleeper
函数,将计数器
生成器作为其参数传递给它。计时器在自己的线程中运行。.start
调用启动计时器,并立即返回,它不会像时间那样等待。sleep
会这样做,因此GUI不会冻结。经过您的解释和一段时间的多次更改,我理解了该功能。谢谢。它完全满足了我的要求。@maheshchaluvadi我很高兴你喜欢它。在这种情况下,Reblochon Masque使用.after
的解决方案稍微简单一些,但了解如何在更复杂的情况下使用Tkinter线程是很有用的。是的,但这种方法的问题是,它不会立即退出循环。它必须完成当前的迭代。只有在那之后才会出来。