Search code examples
pythonuser-interfacelayoutpysimplegui

How to reserve space inside scrollable column in PySimplegUI?


So I want to have a column which is scrollable. There will be plenty of elements inside it. Among other things two canvases that will have matplotlib figures printed.

layout = [[sg.Column(layout, vertical_scroll_only=True, scrollable=True,size=(800,400))]]

I understand now that this reserves space for the column of width 800 and height 400. Inside it you can scroll the allocated space of the elements.

[sg.Button("Load CSVs", key="-loadcsv-")],
[sg.Canvas(key='-CANVAS2-' ),sg.InputText(size=(10,1),key="threshold"), sg.Button("Set Threshold", key="-threshold-")],
[sg.InputText(size=(50, 1), key='-MODELNAME-'), sg.FileBrowse("Load Model")]

This is part of what is inside the column. I understand I can reserve space for the canvas, so that it has some space before the figure is even drawn, but I don't want that look. And also the things after the canvas will still be pushed off the visible space.

How can I allocate the space inside the column?

EDIT: I am adding two pictures, the first is the inital layout:

enter image description here

This is what happens when the matplotlib figure is inserted. Some of it just gets wiped out. I know I can pre-allocated the canvas size, but than I don't like the initial layout. enter image description here


Solution

  • To set size of sg.Canvas to fit figure of Matplotlib, you have better specified option figsize and dpi, then you can get the size will be (figsize[0]*dpi, figsize[1]*dpi).

    Method sg.pin is to keep the position of sg.Canvas when invisible. window['-CANVAS-'].Widget.pack() is to make it visible for no update method of sg.Canvas.

    Method contents_changed called to update scrollbar of sg.column, here window.refresh() required to update GUI before it.

    import matplotlib.pyplot as plt
    import numpy as np
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    import PySimpleGUI as sg
    import matplotlib
    matplotlib.use('TkAgg')
    
    def draw_figure(canvas, figure):
        figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
        figure_canvas_agg.draw()
        figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
        return figure_canvas_agg
    
    column = [
        [sg.Button("Load CSVs", key="-loadcsv-")],
        [sg.pin(sg.Canvas(size=(500, 500), visible=False, key='-CANVAS2-')),
         sg.InputText(size=(10,1), key="threshold"),
         sg.Button("Set Threshold", key="-threshold-")],
        [sg.InputText(size=(50, 1), key='-MODELNAME-'),
         sg.FileBrowse("Load Model")],
    ]
    layout = [[sg.Column(column, vertical_scroll_only=True, scrollable=True, size=(800, 400), key='-COLUMN-')]]
    window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI', layout, finalize=True, element_justification='center', font='Helvetica 18')
    fig_canvas_agg = None
    
    while True:
        event, values = window.read()
        if event == sg.WINDOW_CLOSED:
            break
        elif event == "-threshold-":
            if fig_canvas_agg is None:
                fig = matplotlib.figure.Figure(figsize=(5, 4), dpi=100)
                t = np.arange(0, 3, .01)
                fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
                fig_canvas_agg = draw_figure(window['-CANVAS2-'].TKCanvas, fig)
                window['-CANVAS2-'].Widget.pack()
                window.refresh()
                window['-COLUMN-'].contents_changed()
    
    window.close()