Search code examples
pythongraphpysimpleguimouse-cursor

How do I locate specific rectangles in a PySimpleGUI grid?


I'm new to Python and thus also new to PySimpleGUI.

I have created a grid of rectangles using the code below.

The user selects a rectangle with a left mouse click. If the user drags the mouse over multiple rectangles, all those rectangles are selected. Selected rectangles are highlighted by filling them with colour light green.

What I then want to do is, when the user clicks a button, determine which rectangles they have selected.

`   import PySimpleGUI as sg

    BOX_SIZE = 25

    g = sg.Graph(canvas_size=(125, 125), graph_bottom_left=(0, 0),
                 graph_top_right=(BOX_SIZE * 5, BOX_SIZE * 5), background_color='white',
                 enable_events=True, drag_submits=True,
                 key='-GRAPH-')

    b = sg.Button('Get shaded rectangles')

    layout = [[g,b]] # layout contains a graph and a button

    window = sg.Window('My Window', layout, resizable=True, finalize=True)

    # draw rectangles
    for row in range(5):
        for col in range(5):
            g.draw_rectangle(
                (col * BOX_SIZE, row * BOX_SIZE), # top left
                (col * BOX_SIZE + BOX_SIZE, row * BOX_SIZE + BOX_SIZE), # bottom right
            )

    while True:   # Event Loop
        event, values = window.read()
        if event in (sg.WIN_CLOSED, 'Exit'):
            break
        
        mouse = values['-GRAPH-']

        if event == '-GRAPH-':
            if mouse == (None, None):
                continue

            box_x = mouse[0]//BOX_SIZE
            box_y = mouse[1]//BOX_SIZE
            g.draw_rectangle(
                (box_x * BOX_SIZE, box_y * BOX_SIZE), # top left
                (box_x * BOX_SIZE + BOX_SIZE, box_y * BOX_SIZE + BOX_SIZE), # bottom right
                  fill_color='pale green'
            )

        if event == "Get shaded rectangles":
            print("What do I do?")
        
    window.close()

I really have no idea where to start. I have googled and found 'itemcget'. I don't know if that is useful, and if it is, how to implement it.

I am thinking I need to look at each rectangle and check the fill-color, but I don't know how to go about it.


Solution

  • Try to record which rectangle selected, then you will know what rectangles selected when you click "Get shaded rectangles".

    shaded = set()
    
    while True:   # Event Loop
    ...
            shaded.add((box_x, box_y))
    
        if event == "Get shaded rectangles":
            print("What do I do?")
            print(shaded)
    ...
    

    Selected rectangles are highlighted by filling them with colour light green.

    They are not filled with colour light green. You draw another rectangle on the same place.

    Following code with more code about the itemcget, update fill color for an item by itemconfigure, they need tkinter code here.

    import PySimpleGUI as sg
    
    BOX_SIZE = 25
    
    g = sg.Graph(canvas_size=(125, 125), graph_bottom_left=(0, 0),
        graph_top_right=(BOX_SIZE * 5, BOX_SIZE * 5), background_color='white',
        enable_events=True, drag_submits=True,
        key='-GRAPH-')
    
    b = sg.Button('Get shaded rectangles')
    
    layout = [[g,b]] # layout contains a graph and a button
    
    window = sg.Window('My Window', layout, resizable=True, finalize=True)
    canvas = g.widget
    
    # draw rectangles
    rectangles = []
    for row in range(5):
        for col in range(5):
            rectangle = g.draw_rectangle(
                (col * BOX_SIZE, row * BOX_SIZE), # top left
                (col * BOX_SIZE + BOX_SIZE, row * BOX_SIZE + BOX_SIZE), # bottom right
            )
            rectangles.append(rectangle)
    
    shaded = set()
    
    while True:   # Event Loop
        event, values = window.read()
        if event in (sg.WIN_CLOSED, 'Exit'):
            break
    
        mouse = values['-GRAPH-']
    
        if event == '-GRAPH-':
            if mouse == (None, None):
                continue
    
            box_x = mouse[0]//BOX_SIZE
            box_y = mouse[1]//BOX_SIZE
            rectangle = rectangles[box_x + box_y * 5]
            canvas.itemconfigure(rectangle, fill="pale green")
            shaded.add((box_x, box_y))
    
        if event == "Get shaded rectangles":
            print("What do I do?")
            print(shaded)
            items = []
            for i, rectangle in enumerate(rectangles):
                box_y, box_x = divmod(i, 5)
                if canvas.itemcget(rectangle, "fill") == 'pale green':
                    items.append(i)
            print(items)
    
    window.close()