Итак, у меня есть окно, которое контролируется потоком, который работает в фоновом режиме и при необходимости изменяет графический интерфейс, в какой-то момент этому потоку будет дано указание изменить окно (включая уничтожение окна, в котором оно находится, и запуск другого окна), но этого никогда не происходит, потому что поток не прекратит выполнение до тех пор, пока окно не будет изменено.
Ниже приведен упрощенный пример:
class Window1:
def __init__(...):
self.Master = tk.Tk()
# some code
self.BackgroundUpdates = threading.Thread(target=self.ActiveWindow)
self.BackgroundUpdates.start()
def ActiveWindow(self):
# gets some instruction
if instruction == 'next window':
nextWindow(self)
def StartWindow(self):
self.Master.mainloop()
def KillWindow(self):
self.Master.destroy()
class Window2:
def __init__(...):
self.Master = tk.Tk()
# some code...
def StartWindow(self):
self.Master.mainloop()
def nextWindow(objectWindow):
objectWindow.KillWindow()
# when this function is called it never gets past the line above
nextWindow = Window2()
nextWindow.StartWindow()
application = Window1()
application.StartWindow()
Есть ли способ изменить порядок обработки потока, чтобы не столкнуться с этой проблемой?
работающий пример:
import tkinter as tk
import threading
class MainWindow:
def __init__(self):
self.Master = tk.Tk()
self.Frame = tk.Frame(self.Master, width=100, height=100)
self.Frame.pack()
self.Updates = threading.Thread(target=self.BackgroundUpdates)
self.Updates.start()
def BackgroundUpdates(self):
# imagine instructions to be a really long list with each element being a
# different instruction
instructions = ['instruction1', 'instruction2', 'next window']
while True:
if instructions[0] == 'next window':
ChangeWindow(self)
else:
instructions.remove(instructions[0])
def StartWindow(self):
self.Master.mainloop()
def KillWindow(self):
self.Master.destroy()
class SecondaryWindow:
def __init__(self):
self.Master = tk.Tk()
self.Frame = tk.Frame(self.Master, width=100, height=100)
self.Frame.pack()
def StartWindow(self):
self.Master.mainloop()
def KillWindow(self):
self.Master.destroy()
def ChangeWindow(oldObject):
oldObject.KillWindow()
# the line above will halt the program, since it has to wait on the thread to
# finish before the window can be destroyed, but this function is being called
# from within the thread and so the thread will never stop executing
del oldObject
newObject = SecondaryWindow()
newObject.StartWindow()
window = MainWindow()
window.StartWindow()
@coderoftheday я НАМНОГО упростил его по сравнению с тем, как он есть в моей программе, не знаю, работает ли этот настоящий здесь код, это просто для того, чтобы показать общую проблему.
ну, ваш код недостаточно ясен, чтобы понять ваш вопрос, попробуйте предоставить минимальный воспроизводимый пример
Я понял, что tkinter является однопоточным, это можно объяснить здесь:
https://stackoverflow.com/a/45803955/11702354
Проблема заключалась в том, что я пытался уничтожить свое окно из потока, отличного от того, в котором оно было создано. Чтобы решить эту проблему, мне пришлось использовать метод «после» из модуля Tkinter, а также использовать событие, это означало, что Я мог управлять фоновыми вещами (т.е. ждать определенной команды от моего подключенного сервера), и когда мне нужно было изменить окно, я устанавливал событие.
Часть моего адаптированного кода можно увидеть ниже:
def CheckEvent(self):
if LOBBY_EVENT.is_set():
ChangeWindow(self, 'game')
self.Master.after(5000, self.CheckEvent)
def StartWindow(self):
self.Master.after(5000, self.CheckEvent)
self.Master.after(2000, self.HandleInstruction)
self.Master.mainloop()
Поэтому всякий раз, когда я вызывал метод StartWindow для своего окна, он проверял, установлено ли событие каждые 5 секунд, а затем каждые 2 секунды переходил к отдельной функции «HandleInstruction», которая позволяла мне создавать ответ в моем графическом интерфейсе. (Я также использовал очереди для передачи информации этой функции)
Я надеюсь, что это прояснит путаницу, если кто-то наткнется на это!
ваш код даже не запускается