skip to Main Content

I have a Python application that builds itself using a JSON file, for customization purposes. But, I realized that I have no way of dealing with overflow, and now that it has a lot of stuff it either overflows to the sides or to the bottom.
This is the code that works for small amounts of widgets, but can’t adapt.

def BuildApplication():
    for key in jsonValueDict:
        key = ttk.Label(topContainer, text="Insira a coluna " + jsonValueDict[key])
        key.pack()
        for key in jsonInputDict:
            key = ttk.Entry(topContainer)
            key.pack()
            break
    btnSubmit = ttk.Button(midContainer, text="Finalizar", command=Submit)
    btnSubmit.pack()
    btnExport = ttk.Button(midContainer, text="Exportar", command=Export)
    btnExport.pack()
    print("Finished loading.")

I saw some people talking about using "for x in range" loops but I can’t since it’s based on a dictionary and it can have multiple sizes. I tried using modulus to change it every x amount of widgets, but since I have a label and an input it doesn’t work.

I tried using ‘counter’ variables that increased during iteration, but it either just created a downward stair or just completely messed up the buttons.
I need this to become a grid, "after x amount of widgets, move to the side and start counting again"

2

Answers


  1. Not sure if I understood this correctly but if you have 10 items and try to put it in a grid of 2 rows then you want it to create 5 columns of 2 rows(?). I can’t tell what you are trying to achieve exactly as I don’t know the specification of the two json dictionaries. But assuming that if L = the number of column labels and R = the number of rows then L*R <= number of keys in the input dictionary then I would do something like:

    from tkinter import * 
    from tkinter.ttk import * # overrides default widgets 
    import json
    
    def BuildApplication(Frame):
        def __init__(self, parent, label_path, entry_path, rows): 
            Frame.__init__(self, parent)
            self.rows = rows 
        
            label_dict = json.loads(label_path)
            entry_dict = json.loads(entry_path) 
    
            self.grid_rowconfigure(list(range(rows)), weight=1, uniform="rows")
            self.grid_columnconfigure(list(range(len(label_dict))), weight=1, uniform="cols")
            col_ind = 0 
            for lk in label_dict.keys(): 
                l = Label(self, text=label_dict[lk], font=<whatever font>)
                l.grid(column=col_ind, row=0, sticky="nsew") 
                
                row_ind = 0
                for ek in entry_dict.leys(): 
                    e = Entry(self) 
                    e.insert(0, entry_dict[ek]) 
                    e.grid(column=col_ind, row=row_ind, sticky="nsew")
                    row_ind += 1 
                col_ind += 1 
    

    I think that covers what you want(?). I don’t know where you wanted the buttons so I didn’t add that to the code. I personally recommend grid over pack if you are dealing with a lot of widgets as it is easier to manage placement.

    I did not run this code btw, just typed it straight into stackoverflow.

    Login or Signup to reply.
  2. I can’t reply to comments as my rep is not high enough, but for the problem of getting the widgets to go label button label button in sequence. You can just make two lists of labels and buttons and then start packing or gridding them.

    For example:

    label_dict = json.loads(<filepath>)
    label_list = label_dict.values() 
    
    # do the same thing for buttons if you get it from a json 
    button_list = ... 
    
    # assuming the two lists are of the same length 
    for i in range(len(label_list)): 
        l = Label(<parent>, text = label_list[i]) 
        l.pack() 
        # if you don't have a list for button you can just make them here
        b = Button(<parent>, text = button_list[i]) 
        b.pack() 
    

    Do not that if you do use a for loop to make a bunch of widget and wish to bind them somehow, you need to specify the widget in the bind method in the loop.
    i.e.

    for ...: # some for loop, didn't specify anything 
        w = <Some Widget>
        w.bind("<Some Event>", lambda e, w=w: <some function/code that modifies or uses w>)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search