Я хочу выйти из цикла сразу после нажатия кнопки остановки. Но с этим кодом я смог выйти только после выполнения текущей итерации и последующей итерации.
Это очень важно для моего приложения, так как iam собирается использовать его для автоматизации инструментов, где операции необходимо остановить сразу после нажатия кнопки останова.
# -*- 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()
Вероятно, вам лучше использовать root.after
чем потоки:
В любом случае, как указывалось другим, использование 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()
Как правило, не рекомендуется использовать time.sleep
с программами GUI, потому что он заставляет все спать, поэтому графический интерфейс пользователя не может обновить себя или ответить на события. Кроме того, он становится беспорядочным, когда вы хотите прервать sleep
.
Я адаптировал ваш код для использования Timer
из модуля threading
передачи. Мы можем легко прервать этот Timer
мгновенно, и он не блокирует графический интерфейс.
Чтобы сделать эту работу, я перевел ваш счетчик for
цикл в генератор.
Если вы нажмете кнопку "Пуск" во время подсчета, он скажет вам, что он уже подсчитывает. Когда цикл счета закончен, либо нажав Стоп, либо, дойдя до конца номера, вы можете нажать "Начать снова", чтобы начать новый счет.
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()
delay
а затем вызывает функцию sleeper
, передавая ей генератор counter
качестве аргумента. Таймер работает в своем собственном потоке. .start
запускает Timer и немедленно возвращается, он не ждет, как time.sleep
, поэтому графический интерфейс не time.sleep
.
Без использования отдельного потока вы всегда можете перебирать команду sleep, что сделает код более отзывчивым.
например, это уменьшит ваше ожидание между нажатием кнопки stop и loop на 1/10 секунды, сохраняя 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()
sleep
в потоке GUI, потому что tkinter не может обрабатывать какие-либо события, пока программа спит.
root.update()
мгновенно возвращает управление в основной цикл.
n += 1
вместо генератора. : D