Search code examples
pythonpysimplegui

update size of Scrollable bar in pysimpleGUI


Basically I have the same issue than this one : issue

I tried this before but I get an error message, I think because I am using frames (I think). As you can see I tried using window.visibility_changed() but it did not help.

Test code to explain :

import PySimpleGUI as sg 

def frame (n_frame):
    layout = [[sg.Text  ('test')]]   
    
    return layout

def make_window():
    layout = [[sg.Column([[sg.Text  ('Title')],          # First title of the IDS 
                          [sg.Column(frame(1),key = '-LVL 1 CALL-')],
                          [sg.pin   (sg.Frame(title  = '',
                                              layout = [[sg.Button(' + ',key = '-ADD A LVL 1 FRAME-'),
                                                         sg.Button(' - ',key = '-REMOVE A LVL 1 FRAME-'),
                                                         sg.Button('Save')]],
                                              relief = 'flat'))]],
                        scrollable=True,  
                        vertical_scroll_only=True,
                        pad =(0,0))]]   
    window = sg.Window('Window Title', layout, metadata=1, resizable = True, element_padding = (10, 6), finalize = True)
    return window

def main():
    window = make_window()
    
    while True:
        event, values   = window.read()
        
        if event == sg.WIN_CLOSED or event =='Save':
            break
    
        elif event == '-ADD A LVL 1 FRAME-' : 
            window.metadata += 1 
            window.extend_layout(window['-LVL 1 CALL-'],(frame(window.metadata)))
            window.refresh()
            window.visibility_changed()
            window['-LVL 1 CALL-'].contents_changed()

    window.close()
    
if __name__ == '__main__':
    
    main()

The error message :

File "C:\...\Lib\site-packages\PySimpleGUI\PySimpleGUI.py", line 8302, in contents_changed
    self.TKColFrame.canvas.config(scrollregion=self.TKColFrame.canvas.bbox('all'))
    ^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Frame' object has no attribute 'canvas'

Additional questions :

  • I would like to update the size of it without having to call .contents_changed() on the specific window that has just been added because I have just so many
  • I would like the scrollbar to adapt to the size of the window if the user resize window

These are less important and I can also find by myself, thank you for your help


Solution

  • I would like to update the size of it without having to call .contents_changed() on the specific window that has just been added because I have just so many

    Call method contents_changed only for the scrollable Column element, so here you may add a key, like -Column-, to main scrollable Column element.

    def make_window():
        layout = [[sg.Column([[sg.Text  ('Title')],          # First title of the IDS
                              [sg.Column(frame(1),key = '-LVL 1 CALL-')],
                              [sg.pin   (sg.Frame(title  = '',
                                                  layout = [[sg.Button(' + ',key = '-ADD A LVL 1 FRAME-'),
                                                             sg.Button(' - ',key = '-REMOVE A LVL 1 FRAME-'),
                                                             sg.Button('Save')]],
                                                  relief = 'flat'))]],
                            scrollable=True,
                            vertical_scroll_only=True,
                            pad =(0,0),
                            key="-Column-",                 # Add key here
                            )]]
        window = sg.Window('Window Title', layout, metadata=1, resizable = True, element_padding = (10, 6), finalize = True)
        return window
    

    then you can call method contents_changed of the '-Column-' Column element, like

            elif event == '-ADD A LVL 1 FRAME-' :
                window.metadata += 1
                window.extend_layout(window['-LVL 1 CALL-'],(frame(window.metadata)))
                window.refresh()
                window.visibility_changed()
                window['-Column-'].contents_changed()
    

    I would like the scrollbar to adapt to the size of the window if the user resize window

    It is much complex to make the scrollable Column to expand when it or window configured, following code demo the way about how I do it, and it need more knowledge about the tkinter.

    import PySimpleGUI as sg
    
    def repack(widget, option):
        pack_info = widget.pack_info()
        pack_info.update(option)
        widget.pack(**pack_info)
    
    def configure_canvas(event, canvas, frame_id):
        canvas.itemconfig(frame_id, width=canvas.winfo_width())
    
    def configure_frame(event, canvas):
        canvas.configure(scrollregion=canvas.bbox("all"))
    
    def cell(i):
        layout = [
            [sg.Text('Hello World', expand_x=True, key=f'TA{i}'),
             sg.Text('Hello World', expand_x=True, justification='center', key=f'TB{i}')]
        ]
        return [[sg.Frame(f'Frame {i}', layout, background_color='blue', expand_x=True, key=f'FRAME{i}')]]
    
    
    layout = [
        [sg.Button('New Frame')],
        [sg.Column(cell(0), scrollable=True,  vertical_scroll_only=True, pad=(0, 0), expand_x=True, expand_y=True, key='COLUMN')],
    ]
    location = sg.Window.get_screen_size()
    window = sg.Window('Title', layout, resizable=True, finalize=True, margins=(0, 0), location=location)
    
    repack(window[f'TA{0}'].widget, {'fill':'none', 'expand':0, 'before':window[f'TB{0}'].widget})
    
    column = window['COLUMN'].widget
    frame_id, frame, canvas = column.frame_id, column.TKFrame, column.canvas
    
    canvas.bind("<Configure>", lambda event, canvas=canvas, frame_id=frame_id:configure_canvas(event, canvas, frame_id))
    frame.bind("<Configure>", lambda event, canvas=canvas:configure_frame(event, canvas))
    
    window.set_size((320, 240))
    window.refresh()
    window.move_to_center()
    
    count = 1
    
    while True:
    
        event, values = window.read()
    
        if event == sg.WIN_CLOSED:
            break
        elif event == 'New Frame':
            window.extend_layout(window['COLUMN'], cell(count))
            repack(window[f'TA{count}'].widget, {'fill':'none', 'expand':0, 'before':window[f'TB{count}'].widget})
            count += 1
    
    window.close()