'Pygame Erases Previous Drawing
When I run the draw 3 nodes function, only the final node and link is drawn when I want all 3 nodes and links to be drawn. I did some testing and I believe it draws all of the nodes, but when it moves on to the next node it erases the previous one. I'm not 100% sure if my theory is right.
SCREEN_SIZE = (800, 800) # (width, height)
GRID_SIZE = 8
NODE_WIDTH = 75
NODE_HEIGHT = 50
NODE_COLOUR = (0, 0, 255)
NODE_POSITION = (10, 25)
NODE_SIZE = (75, 50)
LINK_COLOUR = (255, 0, 0)
LINK_START = (NODE_POSITION[0] + 55, NODE_POSITION[1] + 25)
LINK_END = (NODE_POSITION[0] + 103,
NODE_POSITION[1] + 25)
LIST_OF_EVENTS = []
################################################################################
# Pygame helper functions (don't change these!)
################################################################################
def initialize_screen(screen_size: tuple[int, int], allowed: list) -> pygame.Surface:
"""Initialize pygame and the display window.
allowed is a list of pygame event types that should be listened for while pygame is running.
"""
pygame.display.init()
pygame.font.init()
screen = pygame.display.set_mode(screen_size)
screen.fill(THECOLORS['white'])
pygame.display.flip()
pygame.event.clear()
pygame.event.set_blocked(None)
pygame.event.set_allowed([pygame.QUIT] + allowed)
return screen
def draw_text(screen: pygame.Surface, text: str, pos: tuple[int, int]) -> None:
"""Draw the given text to the pygame screen at the given position.
pos represents the *upper-left corner* of the text.
"""
font = pygame.font.SysFont('inconsolata', 22)
text_surface = font.render(text, True, THECOLORS['black'])
width, height = text_surface.get_size()
screen.blit(text_surface,
pygame.Rect(pos, (pos[0] + width, pos[1] + height)))
def draw_grid(screen: pygame.Surface) -> None:
"""Draws a square grid on the given surface.
The drawn grid has GRID_SIZE columns and rows.
You can use this to help you check whether you are drawing nodes and edges in the right spots.
"""
color = THECOLORS['grey']
width, height = screen.get_size()
for col in range(1, GRID_SIZE):
x = col * (width // GRID_SIZE)
pygame.draw.line(screen, color, (x, 0), (x, height))
for row in range(1, GRID_SIZE):
y = row * (height // GRID_SIZE)
pygame.draw.line(screen, color, (0, y), (width, y))
################################################################################
# 1. Drawing nodes and links
################################################################################
def draw_node(screen: pygame.Surface, node: _Node, pos: Tuple[int, int]) -> None:
"""Draw a node on the screen at the given position.
pos represents the coordinates of the *top-left* corner of the node.
Your drawing of the the node should include:
- A rectangle split vertically into two halves.
- The item stored in the node, displayed in the left half.
You may assume the string representation of item is at most 3 characters
long. You'll need to use the draw_text function we've provided above.
NOTE: Do not draw the arrow representing the link to the next node in this function.
You'll implement that part of the visualization separately in the draw_link function.
We strongly recommend initializing new constants at the top of this file to represent
node width, height, and colour.
>>> linky = LinkedList([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
>>> draw_node(initialize_screen(SCREEN_SIZE, LIST_OF_EVENTS), linky.first, NODE_POSITION)
"""
draw_grid(initialize_screen(SCREEN_SIZE, LIST_OF_EVENTS))
pygame.draw.rect(screen, NODE_COLOUR, pygame.Rect(pos, NODE_SIZE), 1)
pygame.draw.line(screen, NODE_COLOUR, (pos[0] + 37, pos[1] + 50), (pos[0] + 37, pos[1]), 1)
draw_text(screen, str(node.item), (pos[0] + 5, pos[1] + 15))
def draw_link(screen: pygame.Surface, start: Tuple[int, int], end: Tuple[int, int]) -> None:
"""Draw a line representing a link from `start` to `end`.
To indicate which end is the "start" of the line, draw a small circle at the starting point
(like the diagrams we've seen in class).
The rest of your link can be a simple line; you may, but are not required, to draw an
arrowhead at the end of the line.
>>> draw_link(initialize_screen(SCREEN_SIZE, LIST_OF_EVENTS), LINK_START, LINK_END)
"""
pygame.draw.circle(screen, NODE_COLOUR, start, 5)
pygame.draw.line(screen, LINK_COLOUR, start, end)
def draw_three_nodes(screen_size: Tuple[int, int]) -> None:
"""Draw three nodes on a pygame screen of the given size.
You may choose the coordinates for the nodes, as long as they do not overlap with each other
and are separated by at least 10 pixels. Each link must start in the CENTRE of the start node's
right half, and must end on the border of the end node (not inside the end node).
This matches the style of node from lecture.
The third node should link to "None", which you should visualize by calling draw_text.
>>> draw_three_nodes(SCREEN_SIZE)
"""
screen = initialize_screen(screen_size, [])
increment = 0
node1 = _Node(1)
node2 = _Node(2)
node3 = _Node(3)
node1.next = node2
node2.next = node3
curr = node1
while curr is not None:
draw_node(screen, node1, (NODE_POSITION[0] + increment, NODE_POSITION[1]))
draw_link(screen, (LINK_START[0] + increment, LINK_START[1]),
(LINK_END[0] + increment, LINK_END[1]))
increment += 100
curr = curr.next
# Don't change the code below (it simply waits until you close the Pygame window)
pygame.display.flip()
pygame.event.wait()
pygame.display.quit()
Solution 1:[1]
Inside the draw_node function, you're reinitializing the screen for drawing each node.
draw_grid(initialize_screen(SCREEN_SIZE, LIST_OF_EVENTS))
I think this is the reason why your screen isn't persistent.
Instead of initializing the screen inside the draw_node function for each individual node, initiliaze it only once in draw_three_nodes.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | desertnaut |
