Cela pourrait être la question la plus compliquée que j'ai posée ici. J'ai passé du temps à obtenir mon code le plus simple possible pour reproduire mon problème. J'espère que ce n'est pas trop compliqué pour obtenir de l'aide ...destroy() tkinter toplevel de la file d'attente échoue silencieusement (condition de concurrence?)
Fondamentalement, dans le code ci-dessous, une application tkinter avec un seul bouton est créée, et elle vérifie une file d'attente toutes les 100ms parce qu'un thread différent peut avoir besoin d'interagir avec elle plus tard. Une nouvelle fenêtre est également créée et détruite très rapidement parce que j'obtiens une erreur plus tard sinon (ceci peut être important)
Lorsque le bouton est cliqué, un nouveau fil est fait qui indique le fil principal (via la file d'attente) pour créer une fenêtre qui serait utilisée pour indiquer que quelque chose de potentiellement long est en train d'arriver, alors quand cela se termine, il indique au thread principal (via la file d'attente) de détruire la fenêtre. Le problème est que la fenêtre n'est pas détruite si la tâche de temps est très courte et il n'y a pas d'erreur non plus, mais si le processus dans le thread a pris beaucoup de temps (une seconde par exemple), cela fonctionne comme prévu . Je me demande si c'est quelque chose comme "Le nouvel objet fenêtre n'a pas encore été créé et affecté à new_window
, alors quand j'ajoute la méthode destroy à la file d'attente, j'ajoute en fait l'ancien objet (précédemment détruit) méthode à la file ". Cela expliquerait pourquoi j'obtiens une erreur la première fois que je clique sur le bouton si je ne crée pas et ne détruis pas la fenêtre quand j'initialise l'application, mais cela n'explique pas pourquoi je n'obtiens pas d'erreur en appelant sur a détruit précédemment Toplevel
... Si je ne me trompe pas avec cette théorie, je ne sais pas vraiment ce que la solution est, donc toutes les idées seraient appréciés
import tkinter as tk
import queue
import threading
import time
def button_pressed():
threading.Thread(target=do_something_on_a_thread).start()
def do_something_on_a_thread():
global new_window
app_queue.put(create_a_new_window)
time.sleep(1)
app_queue.put(new_window.destroy)
def create_a_new_window():
global new_window
new_window = tk.Toplevel()
tk.Label(new_window, text='Temporary Window').grid()
#Check queue and run any function that happens to be in the queue
def check_queue():
while not app_queue.empty():
queue_item = app_queue.get()
queue_item()
app.after(100, check_queue)
#Create tkinter app with queue that is checked regularly
app_queue = queue.Queue()
app = tk.Tk()
tk.Button(app, text='Press Me', command=button_pressed).grid()
create_a_new_window()
new_window.destroy()
app.after(100, check_queue)
tk.mainloop()
BTW, c'est une question bien écrite. Si seulement plus de questions SO étaient si bien écrites, avec un beau MCVE ... :) –