Home > Mobile >  How can I save data from a combobox that is executed in a for loop and have it print the values ​in
How can I save data from a combobox that is executed in a for loop and have it print the values ​in

Time:08-26

I am designing a project that is based on saving information on domestic gas cylinders for a community, first a window is opened where the number of cylinders to be registered is entered, then a combobox with the data already assigned is shown in another window, only select them, when I give the save button the empty values ​​appear help

this is the code

from tkinter import *

from tkinter import Toplevel, getint, ttk

ventana = Tk()

class cilin:
    def __init__(self, empresa, tamano, pico):
    
        self.empresa = empresa.pack(), empresa.bind("<<ComboboxSelected>>", lambda _: empresa.get())
        self.tamano = tamano.pack(), tamano.get()
        self.pico = pico.pack(), pico.get()

    

    def __str__(self):
        return f"Empresa: {self.empresa} , Tamano: {self.tamano} , Pico: {self.pico} "


def ejecucion():
    can = cantidad.get()  1
    ventana2 = Toplevel()

    for cilindros in range(1, can ,1):

        titulo = LabelFrame(ventana2, text= f"Cilindro {cilindros}")
        titulo.pack()

        objeto = cilin(
        empresa = ttk.Combobox(titulo, values=["Radelco", "PacoGas", "Comunal"]), 
        tamano = ttk.Combobox(titulo, values=["Pequena", "Mediana", "Regular", "Grande"]), 
        pico = ttk.Combobox(titulo, values=["Pequeno", "Mediano", "Grande"]))

    def guardar():
        print(*lista)

    lista.append(objeto)
    Button(ventana2, text="Guardar", command=guardar).pack()


lista = []
cantidad = IntVar()

Label(ventana, text="cantidad cilindros").pack()
Entry(ventana, textvariable=cantidad).pack()
Button(ventana, text="listo", command=ejecucion).pack()

ventana.mainloop()

And this is what he throws at the end

Empresa: (None, '18560064<lambda>') , Tamano: (None, '') , Pico: (None, '')

CodePudding user response:

The main problem is that after for example:

self.tamano = tamano.pack(), tamano.get() # Returns: ( None, '' )
# tamano.pack() returns None 
# tamano.get() gets the contents of tamano a few millisecnds after creation.

I've amended your code to save each successive lista into a total_list which prints after the GUI is closed.

from tkinter import *

from tkinter import Toplevel, getint, ttk

ventana = Tk()

class cilin:
    def __init__(self, empresa, tamano, pico):
        # Keep references to the objects
        self.empresa = empresa
        self.tamano = tamano
        self.pico = pico
        # Pack the objects
        empresa.pack()  
        tamano.pack()
        pico.pack()

    def get( self ):
        return self.empresa.get(), self.tamano.get(), self.pico.get()

    def __str__(self):
        # Call get on the Comboboxes to show results. 
        e, t, p  = self.get()
        return f"Empresa: { e } , Tamano: { t } , Pico: { p } "

def ejecucion():
    can = cantidad.get()   1
    ventana2 = Toplevel()
    lista = []  # Make lista local.  It lists the objects in the current ventana2
    for cilindros in range(1, can ,1):
        titulo = LabelFrame(ventana2, text= f"Cilindro {cilindros}")
        titulo.pack()
        objeto = cilin(
        empresa = ttk.Combobox(titulo, values=["Radelco", "PacoGas", "Comunal"]), 
        tamano = ttk.Combobox(titulo, values=["Pequena", "Mediana", "Regular", "Grande"]), 
        pico = ttk.Combobox(titulo, values=["Pequeno", "Mediano", "Grande"]))
        lista.append( objeto )

    def guardar():
        for obj in lista:
            print( obj )
            total_list.append( obj.get() ) # Store the results
        ventana2.destroy() 
        # If not destroyed each call to ejecucion will add more and 
        # more frames and comboboxes which are no longer used.

    Button(ventana2, text="Guardar", command=guardar).pack()


total_list = []  # A new list to accumulate the data collected.
cantidad = IntVar()

Label(ventana, text="cantidad cilindros").pack()
Entry(ventana, textvariable=cantidad).pack()
Button(ventana, text="listo", command=ejecucion).pack()

ventana.mainloop()

print( total_list )

CodePudding user response:

I rewrote your code in a OO way.

To do what you want, if I understand correctly, you have to keep a reference to all the combo widgets you create when the window opens.

Here I use a dictionary and then I loop on it to retrieve the right values, if I understand well what you want to do.

I also set a maximum quantity available, 6, and a check on the text box to see if maybe someone think of ordering 0 ;)

#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox


class UI(tk.Toplevel):
    def __init__(self, parent, items=None):
        super().__init__(name="details")
        
        self.parent = parent
        self.items = items

        self.empresa = ("Radelco", "PacoGas", "Comunal")
        self.tamano = ("Pequena", "Mediana", "Regular", "Grande") 
        self.pico = ("Pequeno", "Mediano", "Grande")
        
        self.dict_cilindros = {}
        self.init_ui()

    def init_ui(self):

        f0 = ttk.Frame(self)
        
        for item in range(self.items):

            msg = "Cilindro {0}".format(item 1)
            f1 = ttk.LabelFrame(f0,text= msg)
            
            ttk.Label(f1, text = "Empresa").pack()
            empresa= ttk.Combobox(f1,state='readonly',values=self.empresa)
            empresa.pack()

            ttk.Label(f1, text = "Tamano").pack()
            tamano = ttk.Combobox(f1,state='readonly',values=self.tamano)
            tamano.pack()

            ttk.Label(f1, text = "Pico").pack()
            pico = ttk.Combobox(f1,state='readonly',values=self.pico)
            pico.pack()

            self.dict_cilindros[item]=(empresa, tamano, pico)

            f1.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
                  
        f2 = ttk.Frame(f0,)

        bts = [("Listo", 0, self.on_listo, "<Alt-l>"),
               ("Cerrar", 0, self.on_cancel, "<Alt-c>")]

        for btn in bts:
            ttk.Button(f2,
                       text=btn[0],
                       underline=btn[1],
                       command = btn[2]).pack(fill=tk.X, padx=5, pady=5)
            self.parent.bind(btn[3], btn[2])
            
        f2.pack(side=tk.RIGHT, fill=tk.Y, expand=0)
        f0.pack(fill=tk.BOTH, expand=1)
        
    def on_open(self):
        msg = "Ha solicitado {0} cilindros".format(self.items)
        self.title(msg)
        
    def on_listo(self, evt=None):
        
        for k,v in self.dict_cilindros.items():
            print("Detalle Cilindro {0}".format(k 1))
            for i in v:
                print(i.get())
                
    def on_cancel(self, evt=None):
        self.destroy()        
        

class Main(ttk.Frame):
    def __init__(self, parent, ):
        super().__init__(name="main")

        self.parent = parent
        self.obj = None
        self.cantidad = tk.IntVar()
        self.cantidad.set(1)
        self.maximo = 6
        self.init_ui()
          
    def init_ui(self):

        f0 = ttk.Frame(self)
        f1 = ttk.Frame(f0,)
      
        ttk.Label(f1, text = "Qantidad Cilindros", ).pack()
        self.txTest = ttk.Entry(f1, textvariable=self.cantidad).pack()        
              
        f2 = ttk.Frame(f0,)

        bts = [("Guardar", 0, self.on_guardar, "<Alt-g>"),
               ("Cerrar", 0, self.on_close, "<Alt-c>")]

        for btn in bts:
            ttk.Button(f2,
                       text=btn[0],
                       underline=btn[1],
                       command = btn[2]).pack(fill=tk.X, padx=5, pady=5)
            self.parent.bind(btn[3], btn[2])
            
        f1.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
        f2.pack(side=tk.RIGHT, fill=tk.Y, expand=0)
        f0.pack(fill=tk.BOTH, expand=1)

    def on_guardar(self, evt=None):
        
        if self.cantidad.get() !=0:

            if self.cantidad.get() <= self.maximo:
                self.obj =  UI(self, self.cantidad.get())
                self.obj.on_open()
            else:
                msg = "Puede solicitar al máximo {0} cilindros.".format(self.maximo)
                messagebox.showinfo(self.master.title(), msg, parent=self)                           
        else:
            msg = "No puedes preguntar cero!"
            messagebox.showinfo(self.master.title(), msg, parent=self)           

    def on_close(self, evt=None):
        if self.obj:
            self.obj.destroy()
        self.parent.on_exit()

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        
        self.protocol("WM_DELETE_WINDOW", self.on_exit)

        self.title("Hello World")
        
        Main(self).pack(fill=tk.BOTH, expand=1)

    def on_exit(self):
        """Close all"""
        msg = "Cerrar?"
        if messagebox.askokcancel(self.title(), msg, parent=self):
            self.destroy()

def main():
    app = App()
    app.mainloop()

if __name__ == '__main__':
    main()            
    

Ventana principal

enter image description here

enter image description here

  • Related