@re3r0

Как решить проблему с видимостью переменной root?

Суть скрипта просто спамить новыми окнами с изображением
from random import randint
import tkinter as tk
from PIL import ImageTk, Image
import telebot;
from time import sleep

bot = telebot.TeleBot('token');

def createNewWindow(root, img):
  for i in range(100):
    newWindow = tk.Toplevel(root)
    labelExample = tk.Label(newWindow, image = img)
    w =  randint(0, newWindow.winfo_screenwidth())
    h =  randint(0, newWindow.winfo_screenheight())
    newWindow.geometry('+{}+{}'.format(w, h))
    labelExample.pack()

@bot.message_handler(content_types=['text'])
def get_command(message):
    if message.text == "Start":
      root = tk.Tk()
      img = ImageTk.PhotoImage(Image.open('lol.png'))
      createNewWindow(root, img)
      root.mainloop()
    elif message.text == "Stop":
      root.destroy()
bot.polling(none_stop=True, interval=0)

после команды Stop в Телеграмм боте выходит ошибка

File "main.py", line 26, in get_command
root.destroy()
UnboundLocalError: local variable 'root' referenced before assignment

Забавно что скприпт после ошибки, все окна закрывает как и надо, но после архиваций в SFX архив окна закрыватся сами по себе не хотят :/

И если не сложно можете подсказать как зациклить скрипт ? что бы после комманды Stop окна закрывались но патом можно было опять начять спам ?
  • Вопрос задан
  • 64 просмотра
Пригласить эксперта
Ответы на вопрос 1
Vindicar
@Vindicar
RTFM!
@bot.message_handler(content_types=['text'])
def get_command(message):
    if message.text == "Start":
      root = tk.Tk()
      img = ImageTk.PhotoImage(Image.open('lol.png'))
      createNewWindow(root, img)
      root.mainloop()
    elif message.text == "Stop":
      root.destroy()

Ух как всё запущено.
Во-первых, если ты ввёл Start, то get_command() создаёт локальную root, настраивает её, и уходит в бесконечный цикл внутри root.mainloop(). Я не знаю как pytelegrambotapi разруливает это, но бот после такого должен просто встать колом, пока все окна не будут закрыты. Подозреваю что обработчик вызывается в отдельном потоке, но фз. В любом случае, не надо так делать. Лучше иметь один root, который крутится внутри mainloop() в отдельном потоке всё время работы скрипта, а окна создавать и удалять по мере надобности, не создавая и не убивая root.
Вообще подружить бота с оконным интерфейсом - задача нетривиальная.
Во-вторых, переменная root - локальная. Она существует только внутри того экземпляра get_command(), который был вызван с командой старт. Если ты вызываешь его с командой Stop, у тебя запускается отдельный экземпляр, где выполняется только ветка Stop - а в этой ветке root объявлен не был, он был объявлен только в ветке Start, в другом экземпляре.
В-третьих, окна будут спамиться только на той машине где запущен бот. Это так, на всякий случай.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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