Cerrar una ventana Tk en proceso

Phil_1857 -  
Diablo76 Mensajes publicados 344 Fecha de registro   Estado Miembro Última intervención   -

Hola,

Tengo un pequeño programa con una interfaz Tkinter que muestra una lista de

palabras en un widget Text, después de un bucle de búsqueda de unos minutos

Para interrumpir la búsqueda, hago clic en la x en la esquina superior derecha de la

barras de título, pero no es muy limpio: me aparece el habitual

"Python no responde Cerrar el programa, ...."

¿Cómo hacer esto de forma más adecuada?

Gracias de antemano

7 respuestas

  1. Diablo76 Mensajes publicados 344 Fecha de registro   Estado Miembro Última intervención   140
     

    Hola Phil,

    No sé si eso cubrirá tus necesidades, pero con el método update() y un binding en la cruz de la ventana, vería algo así:

    import tkinter as tk
    flag = True
    
    def loop():
        i = 0
        while flag:
            i += 1
            print(f"Loop n° {i}")
            root.update()
        print("Loop off")
    
    def on_exit():
        global flag
        flag = False
        root.destroy()
    
    root = tk.Tk()
    but_search = tk.Button(root, text="Search", command=loop)
    but_search.pack()
    but_quit = tk.Button(root, text="Quit", command=on_exit)
    but_quit.pack()
    root.protocol('WM_DELETE_WINDOW', on_exit)
    root.mainloop()
    0
  2. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   Embajador 1 588
     

    hola,

    ¿esto da un mensaje de error cuando cierras la ventana?

    import tkinter
    raíz = tkinter.Tk()
    etiqueta = tkinter.Label(raíz, text="¡Me encanta Python!")
    etiqueta.pack()
    raíz.mainloop()
    print("terminado")
    0
  3. geudin
     

    Hi.

    Indeed, tkinter or any GUI won’t be able to close if we don’t hand control back to it.

    So, the solution isn’t in tkinter but in your search method, which seems to be blocking. Roughly, how is it performed?

    Couldn't you put that in a thread?

    In a very rough summary:

    import tkinter import threading class Search(threading.Thread): def __init__(self, text): super().__init__() self._text = text self._stopped = threading.Event() def run(self): # simulation de qqchose qui prend du temps import time while not self._stopped.is_set(): self._text.insert(tkinter.END, f'{round(time.time())}\n') time.sleep(2) def stop(self): self._stopped.set() def wait_done(ms, window, search): if search.is_alive(): print('waiting...') window.after(ms, wait_done, ms, window, search) else: window.destroy() def on_close(window, search): search.stop() wait_done(100, window, search) def search_run(search, text, button): button.destroy() search.start() window = tkinter.Tk() text = tkinter.Text(window) text.grid() search = Search(text) button = tkinter.Button(window, text='rechercher') button.grid() button.configure(command=lambda: search_run(search, text, button)) window.protocol('WM_DELETE_WINDOW', lambda: on_close(window, search)) window.mainloop()

    ?

    0
    1. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588
       

      No es suficiente llamar regularmente al método update() de tkinter?

      0
  4. Phil_1857
     
    Gracias a todos, Los códigos de Diablo y yg_be funcionan ¿Cómo se realiza mi método de búsqueda? Es un doble bucle para comparar dos listas elemento por elemento, el número de combinaciones puede ser muy grande El código:
    # -*- coding:Utf-8 -*- # 19/04/2024 13:25:08 import itertools as it from tkinter import * def show_result(evt): words_list = [] t1.delete(0.0, END) # Builds anagrams list anag_list = set("".join(e) for e in it.permutations(e1.get(), len(e1.get()))) main_win.update() # Search for el in anag_list: for word in dico: if(el == word): words_list.append(word) if(words_list != []): for el in words_list: t1.insert(END, el+'\n') else: t1.insert(END, 'Rien') def on_exit(): main_win.destroy() WIDTH, HEIGHT = 320, 200 # Makes a list from the dictionnary file dico = [] with open('dico.txt', 'r') as f: for line in f: dico.append(line[:-1]) main_win = Tk() main_win.title('Décoder une anagramme') main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100') main_win.protocol('WM_DELETE_WINDOW', on_exit) l1 = Label(main_win, text='Anagramme :') l1.place(x = 10,y = 20) e1 = Entry(main_win, width = 10) e1.place(x = 100,y = 20) e1.bind("<return>", show_result) e1.focus() t1 = Text(main_win, width = 30, height = 7) t1.place(x = 10, y = 50) main_win.mainloop()</return>
    dico.txt contient 125623 mots un mot de 6 lettres a 720 anagrammes
    0
    1. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588
       

      así sugiero:

       for el in anag_list: main_win.update() if el in dico: words_list.append(el)
      0
    2. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588
       

      No es necesario comparar así todas las parejas de elementos de las dos listas. Es preferible ordenar las dos listas y recorrerlas juntas, para hallar los elementos comunes.

      import itertools as it from tkinter import * def show_result(evt): words_list = [] t1.delete(0.0, END) # Builds anagrams list anag_list = list("".join(e) for e in it.permutations(e1.get(), len(e1.get()))) anag_list.sort() main_win.update() # Search ll1,ll2=len(anag_list),len(dico) i1,i2=0,0 while i1<ll1 and i2<ll2: x1,x2=anag_list[i1],dico[i2] if x1>x2: i2 += 1 elif x1<x2: i1 += 1 else: words_list.append(x1) i1 += 1 i2 += 1 if(words_list != []): for el in words_list: t1.insert(END, el+'\n') else: t1.insert(END, 'Rien') def on_exit(): main_win.destroy() WIDTH, HEIGHT = 320, 200 # Makes a list from the dictionnary file dico = [] with open('dico.txt', 'r') as f: for line in f: dico.append(line[:-1]) dico.sort() main_win = Tk() main_win.title('Décoder une anagramme') main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100') main_win.protocol('WM_DELETE_WINDOW', on_exit) l1 = Label(main_win, text='Anagramme :') l1.place(x = 10,y = 20) e1 = Entry(main_win, width = 10) e1.place(x = 100,y = 20) e1.bind("<Return>", show_result) e1.focus() t1 = Text(main_win, width = 30, height = 7) t1.place(x = 10, y = 50) main_win.mainloop()
      0
      1. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588 > yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención  
         

        Esto permite comparar solo una o dos veces cada palabra del diccionario, en lugar de comparar cada palabra con cada anagrama posible.

        0
  5. Phil_1857
     

    Hola yg_be,

    Así es: hice la prueba antes de leer tu respuesta, pero después de leer

    la de las 11:52

    Funciona muy bien

    Gracias de nuevo a todos, ¡problema resuelto!

    0
    1. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588
       

      También habrás visto que es preferible usar "if ... in ..." en lugar de hacer un bucle.

      0
  6. Diablo76 Mensajes publicados 344 Fecha de registro   Estado Miembro Última intervención   140
     

    Creo que también se puede optimizar el código creando un diccionario a partir de la lista de palabras, tomando como clave la longitud, y creando ana_set a medida que se itera para controlar los boúblons:

    import itertools as it from tkinter import * def show_result(evt): t1.delete(0.0, END) it_perm = it.permutations(e1.get()) anag_set = set() for perm in it_perm: word = "".join(perm) if not len(word) in dico.keys(): break if word in dico[len(word)] and word not in anag_set: t1.insert(END, word+"\n") anag_set.add(word) if not anag_set: t1.insert(END, 'Rien') def on_exit(): main_win.destroy() WIDTH, HEIGHT = 320, 200 dico = {} with open('dico.txt', 'r') as f: for line in f: line = line.strip() longueur_mot = len(line) if longueur_mot not in dico: dico[longueur_mot] = [line] else: dico[longueur_mot].append(line) main_win = Tk() main_win.title('Décoder una anagrama') main_win.geometry(f"{WIDTH}x{HEIGHT}+400+100") main_win.protocol('WM_DELETE_WINDOW', on_exit) l1 = Label(main_win, text='Anagramme :') l1.place(x=10, y=20) e1 = Entry(main_win, width=10) e1.place(x=100, y=20) e1.bind("<Return>", show_result) e1.focus() t1 = Text(main_win, width=30, height=7) t1.place(x=10, y=50) main_win.mainloop() 

    je pense que ça peut être encore optimiser

    0
    1. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588
       

      Todas las permutaciones de la misma longitud:

      def show_result(evt): t1.delete(0.0, END) it_perm = it.permutations(e1.get()) lenw=len(e1.get()) anag_set = set() if lenw in dico.keys(): dicol=dico[lenw] for perm in it_perm: word = "".join(perm) if word in dicol: t1.insert(END, word+"\n") anag_set.add(word) if not anag_set: t1.insert(END, 'Rien')
      0
      1. Diablo76 Mensajes publicados 344 Fecha de registro   Estado Miembro Última intervención   140 > yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención  
         

        No tienes en cuenta los duplicados generados por it.permutations() para la visualización, de lo contrario anag_set no sirve para mucho.

        0
      2. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588 > Diablo76 Mensajes publicados 344 Fecha de registro   Estado Miembro Última intervención  
         
        ¿Por qué probar si cada duplicado está en el diccionario? Es mejor eliminarlos desde el inicio: it_perm = set(it.permutations(e1.get()))
        0
  7. Phil_1857
     

    J'ai fini par faire ceci, et ça marche pas mal:

    # -*- coding=Utf-8 -*- # 19/04/2024 13:25:08 import itertools as it from time import perf_counter from tkinter import * def time_format(_time): units = 's' if(_time > 60.0): _time, units = _time/60.0, 'mn' return(_time,units) def show_result(evt): # Makes a list from the dictionnary file dico = [] with open('dico.txt', 'r') as f: for line in f: if(len(line[:-1]) == len(e1.get())): dico.append(line[:-1]) words_list = [] t1.delete(0.0, END) l3['text'] = 'Temps passé : ' # Builds anagrams list avoiding doubles anag_list = set("".join(e) for e in it.permutations(e1.get(), len(e1.get()))) estimated_t, units = time_format((len(anag_list) * len(dico))/LOOPS_PER_SECOND) l2['text'] = 'Temps estimé : {:.2f} {}'.format(estimated_t, units) # Search t1.configure(cursor = 'wait') start = perf_counter() for el in anag_list: main_win.update() if(el in dico): t1.insert(END, el+'\n') end = perf_counter() t1.configure(cursor = '') elapsed_t, units = time_format(end-start) l3['text'] = f'Temps passé: {elapsed_t: 0.2f} {units} ' def on_exit(): main_win.destroy() LOOPS_PER_SECOND = 16056487 VOWELS = 'aeiouy' WIDTH, HEIGHT = 320, 200 main_win = Tk() main_win.title('Décoder une anagramme') main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+400+100') main_win.protocol('WM_DELETE_WINDOW', on_exit) l1 = Label(main_win, text='Anagramme :') l1.place(x = 10,y = 20) e1 = Entry(main_win, width = 10) e1.place(x = 100,y = 20) e1.bind("<Return>", show_result) e1.focus() l2 = Label(main_win, text='Temps estimé :') l2.place(x = 170,y = 20) t1 = Text(main_win, width = 30, height = 7) t1.place(x = 10, y = 50) l3 = Label(main_win, text='Temps passé :') l3.place(x = 10,y = 170) main_win.mainloop() 
    0
    1. Diablo76 Mensajes publicados 344 Fecha de registro   Estado Miembro Última intervención   140
       

      En mi caso no funciona.

      Trazas:

      Traceback (most recent call last): File "/usr/lib/python3.10/tkinter/__init__.py", line 1921, in __call__ return self.func(*args) File "/home/diablo76/Bureau/Test_Python/pythonTest/bon.py", line 39, in show_result t1.configure(cursor = 'wait') File "/usr/lib/python3.10/tkinter/__init__.py", line 1675, in configure return self._configure('configure', cnf, kw) File "/usr/lib/python3.10/tkinter/__init__.py", line 1665, in _configure self.tk.call(_flatten((self._w, cmd)) + self._options(cnf)) _tkinter.TclError: bad cursor spec "wait"
      0
    2. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588
       

      una pena releer así el archivo cada vez.

      0
      1. Diablo76 Mensajes publicados 344 Fecha de registro   Estado Miembro Última intervención   140 > yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención  
         
        Estoy absolutamente de acuerdo y con mis mixts que te hicieron, ¿tienes una solución?
        0