Почему поток запускается только 1 раз?

Есть вот такой код, при нажатии кнопки запускается цикл в отдельном потоке и все работает нормально, но при повторном нажатии вылетает ошибка

File "C:\Users\di\AppData\Local\Programs\Python\Python36-32\lib\threading.py", line 842, in start raise RuntimeError("threads can only be started once")
RuntimeError: threads can only be started once

from tkinter import *
import time
from threading import Thread


class But_print(Thread):
	def __init__(self):
		super().__init__()
		self.but = Button(root)
		self.but["text"] = "to count"
		self.but.bind("<Button-1>", self.printer)
		self.but.pack()

	def printer(self, event):
		self.start()
		
	def run(self):
		for i in range(10):
			print(10 - i - 1, "second")
			time.sleep(1)

root = Tk()
obj = But_print()
root.mainloop()


Почему? И как это исправить? Нужно что бы при каждом нажатии цикл запускался заново.
  • Вопрос задан
  • 2692 просмотра
Пригласить эксперта
Ответы на вопрос 1
@iSergios
Python-разработчик
Ну во-первых, цикл у вас запускается не в отдельном потоке, а в том же потоке, что и окно. Это замечательно видно по тому, что окно фризится, пока цикл работает (не двигается, не ресайзится). То, что вы унаследовались от Thread еще не означает, что все, что вы запустите, будет работать в отдельном потоке. Пока у вас все в один поток идет. Оттуда, к слову, и ошибка - метод start() может быть вызван только один раз на один поток.

Простейший способ решить вашу задачу таков:
from tkinter import *
import time
import threading


class But_print():
    def __init__(self):
        self.but = Button(root)
        self.but["text"] = "to count"
        self.but.bind("<Button-1>", self.printer)
        self.but.pack()

    def thread(func):
        '''
        Это простейший декоратор. В него мы будем заворачивать 
        функции. Любая функция, завернутая этим декоратором, 
        будет выполнена в отдельном потоке.
        '''
        def wrapper(*args, **kwargs):
            current_thread = threading.Thread(
                target=func, args=args, kwargs=kwargs)
            current_thread.start()

        return wrapper

    @thread  # собственно, применяем декоратор
    def printer(self, event):
        for i in range(10):
            print(10 - i - 1, "second")
            time.sleep(1)


root = Tk()
obj = But_print()
root.mainloop()
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы