How to resize a Graph element after window resize in PySimpleGUI

Viewed 71

I have a GUI in Python using PySimpleGUI with a Graph element (drawing canvas) on it. I want the user to be able to resize the window. The drawing (Graph element) should resize along with the window (as well as all the drawing elements on the Graph element).

I tried the following code, but the resizing doesn't work. Either the circle remains the same size in pixels, regardless of the window size (current code) or the circle does resize, but resizing the Graph element triggers a Window resize event by itself (uncomment line 13 with the graph.set_size() method)

Question: how to resize the Graph element together with the Window, and also resize the elements on the Graph canvas. In the example code: I want the circle to resize so that it fits inside the window.

import PySimpleGUI as sg


INIT_SIZE_PX = (100, 100)
COORD_SYSTEM = [(0, 0), (2, 2)]
CIRCLE_CENTER = (1, 1)
CIRCLE_RADIUS = 1
CIRCLE_COLOR = 'red'


def draw_graph(graph, size):
    graph.erase()
    # graph.set_size(size)  # NOT the way, triggers resize events on its own
    # graph.change_coordinates(*COORD_SYSTEM)  # Not necessary
    graph.draw_circle(CIRCLE_CENTER, CIRCLE_RADIUS, fill_color=CIRCLE_COLOR)


layout = [[
    sg.Graph(INIT_SIZE_PX, *COORD_SYSTEM, key='graph',
             expand_x=True, expand_y=True)
]]
window = sg.Window('Window title', layout=layout,
                   finalize=True, resizable=True)
window.bind('<Configure>', "Resize_Event")
draw_graph(window['graph'], window.size)

while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED or event == 'Exit':
        break

    elif event == "Resize_Event":
        new_size = (int(window.size[0] * 0.9), int(window.size[1] * 0.9))
        draw_graph(window['graph'], new_size)
        print(f"Resized to: {window.size=}; {window['graph'].Size=}")

window.close()
1 Answers

Here, only the coordinate changed for all the items on Graph element, all other features kept the same, like line width, image, text. If more detail update for items on Graph element required, maybe you need to write the code for graph.widget.scale method.

from random import randint
import PySimpleGUI as sg

def random_color():
    return '#%02X%02X%02X' % (randint(0,255), randint(0,255), randint(0,255))

size = (640, 480)
layout = [
    [sg.Graph(size, (0, 0), size, background_color='green', expand_x=True, expand_y=True, pad=(0, 0), key='Graph')],
    [sg.Push(), sg.Button('Plot')],
]
window = sg.Window('Title', layout, resizable=True, margins=(0, 0), finalize=True)
graph, plot = window['Graph'], window['Plot']

## Change the pack order of Graph (row frame) to laste one.
graph_row_frame_pack_info = graph.widget.master.pack_info()
plot_row_frame_pack_info = plot.widget.master.pack_info()
plot_row_frame_pack_info['side'] = 'bottom'
plot.widget.master.pack(**plot_row_frame_pack_info)
graph.widget.master.pack(**graph_row_frame_pack_info)

graph.bind('<Configure>', ' Configure')

while True:

    event, values = window.read()

    if event == sg.WIN_CLOSED:
        break
    elif event == 'Graph Configure':
        e = graph.user_bind_event
        w0, h0 = graph.CanvasSize
        # Update the canvas size for coordinate conversion
        w1, h1 = graph.CanvasSize = e.width, e.height
        w_scale, h_scale = w1/w0, h1/h0
        graph.widget.scale("all", 0, 0, w_scale, h_scale)
    elif event == 'Plot':
        graph.erase()
        graph.draw_rectangle((100, 100), (540, 380), fill_color=random_color())
        graph.draw_arc((100, 380), (540, 430), 180, 180, fill_color=random_color())
        graph.draw_circle((320, 240), 140, fill_color=random_color())
        graph.draw_image(data=sg.EMOJI_BASE64_HAPPY_LAUGH, location=(100, 380))
        graph.draw_text('Hello World', location=(320, 240))

window.close()

enter image description here enter image description here

Related