while utiliza terminar que para for ejemplos dentro como ciclo bucle python-3.x tkinter while-loop user-input

python-3.x - terminar - para que se utiliza while en python



¿Cómo detener un ciclo while para obtener información del usuario que usa Tkinter? (2)

es increíble cómo el conocimiento de algo tan básico puede ser enterrado en un lugar tan difícil de encontrar. Pasé cerca de un mes buscando una respuesta en Google - viendo videos, leyendo documentos, libros, etc. - de cómo detener un ciclo while para obtener información de un usuario que usa Tkinter.

Mi código a continuación está haciendo un bucle dos veces y abandonando el ciclo antes de que pueda proporcionar una entrada.

De todos modos, la teoría es apreciada, pero un código de muestra será de mayor ayuda. Muchas gracias, muchísimo.

# Python 3.5.1 from tkinter import * from tkinter import ttk loop = 0 while loop < 2: print (''loop'') def user_data(): user_input = data.get() print (user_input) lb=ttk.Label(root, text="Enter data") data=ttk.Entry(root) bt=ttk.Button(root, text=''Ok'', command=user_data) lb.grid(row=0, column=1) data.grid(row=0, column=2) bt.grid(row=0, column=3) loop += 1 print (''left loop'') root.mainloop()


Ok, después de mucho debate, parece que en realidad no necesitas esperar nada. Una GUI se encuentra en un estado perpetuo de espera por los eventos, por lo que no necesita agregar esperas adicionales. Todo lo que necesita es un botón de "guardar" y una forma para que el usuario ingrese una cantidad variable de valores.

Para permitir que el usuario ingrese valores múltiples, puede agregar un botón que agregue más widgets de entrada. El único truco real es mantener una lista de los widgets de entrada para que pueda obtener los valores más tarde en su programa.

El siguiente es un ejemplo de trabajo que ilustra la técnica.

Nota: Esta no es la forma en que realmente haría esto en una GUI real porque depende de variables globales. El objetivo es ilustrar el principio general de agregar dinámicamente widgets de entrada.

import tkinter as tk def add_entry(): """ Add two entries, one for a description, one for an amount, along with some labels """ # create the label and entry widgets label1 = tk.Label(entry_frame, text="Description:") label2 = tk.Label(entry_frame, text="Amount:") entry1 = tk.Entry(entry_frame) entry2 = tk.Entry(entry_frame) # lay them out on the screen column, row = entry_frame.grid_size() label1.grid(row=row, column=0, sticky="e", pady=2) entry1.grid(row=row, column=1, sticky="ew", pady=2, padx=4) label2.grid(row=row, column=2, sticky="e", pady=2) entry2.grid(row=row, column=3, sticky="ew", pady=2, padx=4) entry_frame.grid_rowconfigure(row, weight=0) entry_frame.grid_rowconfigure(row+1, weight=1) # save the entries, so we can retrieve the values entries.append((entry1, entry2)) # give focus to the new entry widget entry1.focus_set() def save(): # iterate over the entries, printing the values for description_entry, value_entry in entries: print("description: %s value: %s" % (description_entry.get(), value_entry.get())) # this is our global list of entries entries = [] # create the main window and buttons root = tk.Tk() entry_frame = tk.Frame(root) button_frame = tk.Frame(root) entry_frame.pack(side="top", fill="both", expand=True) button_frame.pack(side="bottom", fill="x") add_button = tk.Button(button_frame, text="add another entry", command=add_entry) save_button = tk.Button(button_frame, text="Save", command=save) add_button.pack(side="left") save_button.pack(side="right") # create the first entry add_entry() # start the main loop -- this is where the GUI starts waiting, # and why you don''t need to add your own loop. root.mainloop()


Ok, creo que la broma está en mí después de todo. :-) Pasé los últimos tres días diciéndote que esto no se puede hacer fácilmente, y resulta que estaba equivocado.

Te daré el código pronto, solo déjame explicarte dónde me equivoqué. Mientras escribía mi último comentario, lo principal que quería explicarte es que cuando ejecutas un programa Python de consola dentro de una consola GUI, esos son dos procesos diferentes, y el bucle de evento de una GUI no tiene nada que ver con cómo el programa interno de Python funciona.

En una aplicación GUI, se descompone ya que solo hay un proceso y su ciclo de eventos no se puede ejecutar al mismo tiempo (responde a eventos normales de la aplicación como volver a pintar una ventana o manejar clics / presionar teclas) y permanecer bloqueado (esperar a que haga clic en un botón). Se me ocurrió que las cosas serían muy simples si tkinter permitiera al usuario crear bucles de eventos adicionales. No es irracional: ya que tkinter ya construye uno para sus propios fines, solo necesita exponer ese constructor (u otro medio de construcción) al usuario. Y no habrá ningún problema GIL, ya que el otro ciclo de eventos simplemente permanece bloqueado (solo uno se está ejecutando realmente).

Una vez que supe lo que estaba buscando, no fue tan difícil de encontrar: usted construye una variable Tk (de cualquier tipo, Boolean funciona bien para esta semántica), alternar su valor y alternarla en la devolución de llamada. Mientras tanto esperas a que cambie. Muy fácil. :-)

Traté de cambiar tu código lo menos posible, pero, por supuesto, una vez que conoces el mecanismo, puedes hacerlo mucho mejor. Espero haber devuelto tu fe en tkinter. :-)

from tkinter import * from tkinter import ttk root = Tk() loop = 0 block = BooleanVar(root, False) while loop < 2: print (''loop'') def user_data(): user_input = data.get() print (user_input) block.set(False) lb=ttk.Label(root, text="Enter data") data=ttk.Entry(root) bt=ttk.Button(root, text=''Ok'', command=user_data) lb.grid(row=0, column=1) data.grid(row=0, column=2) bt.grid(row=0, column=3) block.set(True) root.wait_variable(block) loop += 1 print (''left loop'') root.mainloop()