pythontkinterpysimplegui

Dynamic layout on pysimpleGUI with frames


(Explanation of my problem at the end)

Here is an example of a dynamic layout that add a Frame when I click on a button. Launch state of the program :

enter image description here

Then after button pressed :

enter image description here

Here is the code :

import PySimpleGUI as sg                        

def layout_for_frame(lvl_1):
    layout = [[sg.Frame(title  = 'Frame level 2',
                        layout = [[sg.Text('Text 2 '), sg.Input(key=('-level two-',lvl_1))],
                                  [sg.Combo(['A', 'B'],key=('-combo-',lvl_1))]],
                        relief = 'sunken')]]
    return layout
    
def make_window():
    layout = [[sg.Frame(title  = 'Frame level 1',
                        layout = layout_for_frame(0),
                        key    = '-Frame lvl 1-',
                        relief = 'groove')],
              [sg.Button('+',key = 'add a level two Frame')]]
    
    window = sg.Window('Window Title', layout,metadata=0)
    return window

def main():
    window = make_window()
    while True:
        event, values = window.read()
        print(event, values)
        if   event == sg.WIN_CLOSED : 
            break
        elif event == 'add a level two Frame' : 
            window.metadata += 1            
            window.extend_layout(window['-Frame lvl 1-'],(layout_for_frame(window.metadata)))
    window.close()

if __name__ == '__main__':
    main()

This works perfectly for adding a frame inside another one. The problem is adding another Frame level 1. Because I don't know how to call a function with a key without an element in the layout :

layout = [[(layout_for_frame(0),key = '-CALL FOR FRAME-')],
          [sg.Button('+',key = 'add a level one Frame')]]

This does not work, and so I can't use the same logic shown before.

My question is how to add directly a level 1 frame with a button ?

Please let me know if it is not clear, and thank you for taking the time to read through it.


Solution

  • Ok I figured out the answer :

    It's simple really, when you call the extend window, you just let it on the main window, and then everything that is in the function, will be displayed in the main window. So you just make the Frame level 1 in the function, like so :

    def layout_for_frame(lvl_1):
        layout = [[sg.Frame(title  = f'N° {lvl_1} Frame level 1',
                            layout = [[sg.Frame(title  = 'Frame level 2',
                                                layout = [[sg.Text('Text 2 '), sg.Input(key=('-level two-',lvl_1))],
                                                          [sg.Combo(['A', 'B'],key=('-combo-',lvl_1))]],
                                                relief = 'sunken')],
                                      [sg.Button('Add LVL 2 frame')]],
                            key    = ('-Frame lvl 1-',lvl_1),
                            relief = 'groove')]]
                                      
        return layout
    

    and then when the layout becomes :

    layout = [[layout_for_frame(0)],
              [sg.Button('+',key = 'add a level one Frame')]]
    

    and for the call :

    elif event == 'add a level one Frame' : 
        window.metadata += 1            
        window.extend_layout(window,(layout_for_frame(window.metadata)))
    

    Then the result is this :

    enter image description here

    The only problem is the button not staying at the bottom, Would you know how to solve this ?