pythonpython-3.xzelle-graphics

Is it possible to undraw a previously drawn shape from a loop? Zelle Graphics Python


I was wondering if it was possible to undraw previously drawn shapes from a loop. I have this function that'll create squares on click however I want to make it so that when the same area is clicked a second time the square will undraw.

from graphics import *


def createGrid():
    X = 0
    Y = 0
    gridSize = 5
    for i in range(1, gridSize + 1):
        for j in range(1, gridSize + 1):
            gridSquare = Rectangle(Point(X, Y), Point(X + 100, Y + 100))
            gridSquare.draw(win)
            X = X + 100
        Y = Y + 100
        X = 0


def editMode():
    SelectedSquare = []
    instruction = input("> ")
    if instruction == "s":
        selectionMode(SelectedSquare)


def selectionMode(SelectedSquare):
    editSquare = Rectangle(Point(0, 0), Point(20, 20))
    editSquare.setFill("black")
    editSquare.draw(win)
    while True:
        selection = win.getMouse()
        clickXPos = selection.getX()
        clickYPos = selection.getY()
        if clickXPos > 20 and clickYPos > 20:
            PosX, PosY = clickXPos - (clickXPos % 100), clickYPos - (clickYPos % 100)
            SelectedSquare = SelectedSquare + [Point(PosX, PosY)]
            rect = Rectangle(Point(PosX, PosY), Point(PosX + 100, PosY + 100))
            rect.setWidth(5)
            rect.draw(win)
        else:
            editSquare.undraw()
            break


win = GraphWin("GRID", 500, 500)
createGrid()
while True:
    editMode()

As you can see, on click, there will be a thicker border around the grid square that was selected, I would like to be able to 1) remove the thickened border if clicked a second time 2) be able to remove all thickened borders surrounding grid squares but I just cannot seem to figure this out, any help would be greatly appreciated!


Solution

  • The general problem seems to be that you have no underlying data structure or logic for your program -- you're drawing the interface first and then trying to make its behaviors define the program.

    Below I've patched your code to have the points on the selected squares list remember what rectangle was drawn to highlight them, so if they are selected again, the highlight can be undone and the point removed:

    from graphics import *
    
    GRID_SIZE = 5
    SQUARE_SIZE = 100
    EDIT_BUTTON_SIZE = 20
    BORDER_WIDTH = 5
    
    def createGrid():
        X, Y = 0, 0
    
        for _ in range(1, GRID_SIZE + 1):
            for _ in range(1, GRID_SIZE + 1):
                gridSquare = Rectangle(Point(X, Y), Point(X + SQUARE_SIZE, Y + SQUARE_SIZE))
                gridSquare.draw(win)
                X += SQUARE_SIZE
    
            Y += SQUARE_SIZE
            X = 0
    
    def editMode():
        selectedSquares = []
        instruction = input("> ")
    
        if instruction == "s":
            selectionMode(selectedSquares)
    
    def checkSelected(point, squares):
        for selected in squares:
            if point.getX() == selected.getX() and point.getY() == selected.getY():
                return selected
    
        return None
    
    def selectionMode(selectedSquares):
        editSquare = Rectangle(Point(0, 0), Point(EDIT_BUTTON_SIZE, EDIT_BUTTON_SIZE))
        editSquare.setFill("black")
        editSquare.draw(win)
    
        while True:
            selection = win.getMouse()
            clickXPos = selection.getX()
            clickYPos = selection.getY()
    
            if clickXPos <= EDIT_BUTTON_SIZE and clickYPos <= EDIT_BUTTON_SIZE:
                break
    
            PosX, PosY = clickXPos - clickXPos % SQUARE_SIZE, clickYPos - clickYPos % SQUARE_SIZE
            point = Point(PosX, PosY)
            selected = checkSelected(point, selectedSquares)
    
            if selected:
                selected.rect.undraw()
                selectedSquares.remove(selected)
            else:
                rect = Rectangle(point, Point(PosX + SQUARE_SIZE, PosY + SQUARE_SIZE))
                rect.setWidth(BORDER_WIDTH)
                rect.draw(win)
    
                point.rect = rect
    
                selectedSquares.append(point)
    
        editSquare.undraw()
    
    win = GraphWin("GRID", GRID_SIZE * SQUARE_SIZE, GRID_SIZE * SQUARE_SIZE)
    
    createGrid()
    
    while True:
        editMode()
    

    But this is only a band-aid -- as you add more functionality the issue of a lack of data structure and spelled out logic will continue to frustrate you.