Как убить time.sleep () в Python 3, пока компилятор спит

1

Я хочу выйти из цикла сразу после нажатия кнопки остановки. Но с этим кодом я смог выйти только после выполнения текущей итерации и последующей итерации.

Это очень важно для моего приложения, так как 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()
Теги:
tkinter

3 ответа

1
Лучший ответ

Вероятно, вам лучше использовать 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()
  • 0
    Да, это немного проще, чем моя версия. Но вы "обманули", используя n += 1 вместо генератора. : D
  • 0
    Сладкий. Одно дело, форматированные строковые литералы с префиксом 'f' были введены только в Python 3.6
Показать ещё 2 комментария
2

Как правило, не рекомендуется использовать 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()
  • 0
    Это служит цели. Пожалуйста, объясните, как здесь работает my_timer = Timer (delay, sleeper, (counter,)).
  • 0
    @maheshchaluvadi Создает таймер, который спит в течение секунд delay а затем вызывает функцию sleeper , передавая ей генератор counter качестве аргумента. Таймер работает в своем собственном потоке. .start запускает Timer и немедленно возвращается, он не ждет, как time.sleep , поэтому графический интерфейс не time.sleep .
Показать ещё 6 комментариев
-2

Без использования отдельного потока вы всегда можете перебирать команду 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()
  • 1
    Вы никогда не должны вызывать sleep в потоке GUI, потому что tkinter не может обрабатывать какие-либо события, пока программа спит.
  • 0
    @BryanOakley Учитывая, что OP задал вопрос, в частности, с помощью сна, я решил дать ответ, который соответствует этому вопросу. Я не использую tkinter, но я думал, что root.update() мгновенно возвращает управление в основной цикл.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню