Allowing resizing window pyGame

Question:

I am trying to allow resizing for this app, I put the RESIZABLE flag, but when I try to resize, it messes up! Try my code.

It is a grid program, when the window resizes I want the grid to also resize/shrink.

import pygame,math
from pygame.locals import *
# Define some colors
black    = (   0,   0,   0)
white    = ( 255, 255, 255)
green    = (   0, 255,   0)
red      = ( 255,   0,   0)

# This sets the width and height of each grid location
width=50
height=20
size=[500,500]
# This sets the margin between each cell
margin=1


# Initialize pygame
pygame.init()

# Set the height and width of the screen

screen=pygame.display.set_mode(size,RESIZABLE)

# Set title of screen
pygame.display.set_caption("My Game")

#Loop until the user clicks the close button.
done=False

# Used to manage how fast the screen updates
clock=pygame.time.Clock()

# -------- Main Program Loop -----------
while done==False:
    for event in pygame.event.get(): # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done=True # Flag that we are done so we exit this loop
        if event.type == pygame.MOUSEBUTTONDOWN:
            height+=10

    # Set the screen background
    screen.fill(black)

    # Draw the grid
    for row in range(int(math.ceil(size[1]/height))+1):
        for column in range(int(math.ceil(size[0]/width))+1):
            color = white
            pygame.draw.rect(screen,color,[(margin+width)*column+margin,(margin+height)*row+margin,width,height])

    # Limit to 20 frames per second
    clock.tick(20)

    # Go ahead and update the screen with what we've drawn.
    pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit ()

Please tell me whats wrong, thanks.

Asked By: user1513192

||

Answers:

You are not updating your width, height, or size when the window changes.

From the docs: http://www.pygame.org/docs/ref/display.html

If the display is set with the pygame.RESIZABLE flag,
pygame.VIDEORESIZE events will be sent when the user adjusts the
window dimensions.

You can get the new size, w, h from the event VIDEORESIZE http://www.pygame.org/docs/ref/event.html

Answered By: ninMonkey

A simple Hello World window that is resizable, plus I was playing around with classes.
Broken down into two files, one for defining the colour constants.

import pygame, sys
from pygame.locals import *
from colors import *


# Data Definition
class helloWorld:
    '''Create a resizable hello world window'''
    def __init__(self):
        pygame.init()
        self.width = 300
        self.height = 300
        DISPLAYSURF = pygame.display.set_mode((self.width,self.height), RESIZABLE)
        DISPLAYSURF.fill(WHITE)

    def run(self):
        while True:
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == VIDEORESIZE:
                    self.CreateWindow(event.w,event.h)
            pygame.display.update()

    def CreateWindow(self,width,height):
        '''Updates the window width and height '''
        pygame.display.set_caption("Press ESC to quit")
        DISPLAYSURF = pygame.display.set_mode((width,height),RESIZABLE)
        DISPLAYSURF.fill(WHITE)


if __name__ == '__main__':
    helloWorld().run()

colors.py:

BLACK  = (0, 0,0)
WHITE  = (255, 255, 255)
RED    = (255, 0, 0)
YELLOW = (255, 255, 0)
BLUE   = (0,0,255)

GREEN = (0,255,0)
Answered By: JMJ

The answer for this problem (allow the Pygame window and the surface inside it to resize) is simply to recreate the resizable window with an updated size, when the user changes its dimensions (done on pygame.VIDEORESIZE events).

>>> import pygame
>>> help(pygame.display.set_mode)
Help on built-in function set_mode in module pygame.display:

set_mode(...)
    set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0) -> Surface
    Initialize a window or screen for display
>>> 

This removes all previous content on the window surface, so below
there’s a process to continue with the current window content.

Some example code:

import pygame, sys

pygame.init()
# Create the window, saving it to a variable.
surface = pygame.display.set_mode((350, 250), pygame.RESIZABLE)
pygame.display.set_caption("Example resizable window")

while True:
    surface.fill((255,255,255))

    # Draw a red rectangle that resizes with the window.
    pygame.draw.rect(surface, (200,0,0), (surface.get_width()/3,
      surface.get_height()/3, surface.get_width()/3,
      surface.get_height()/3))

    pygame.display.update()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()

        if event.type == pygame.VIDEORESIZE:
            # There's some code to add back window content here.
            surface = pygame.display.set_mode((event.w, event.h),
                                              pygame.RESIZABLE)

How to continue with the current window content:
Here’s some steps to add back the previous window content:

  1. make a second variable, set to the value of the old window surface variable.
  2. create the new window, storing it as the old variable.
  3. draw the second surface onto the first one (old variable) – use the blit function.
  4. use this variable and delete the new variable (optional, use del) to not use extra memory.

Some example code for the above steps (replaces pygame.VIDEORESIZE event if statement):

        if event.type == pygame.VIDEORESIZE:
            old_surface_saved = surface
            surface = pygame.display.set_mode((event.w, event.h),
                                              pygame.RESIZABLE)
            # On the next line, if only part of the window
            # needs to be copied, there's some other options.
            surface.blit(old_surface_saved, (0,0))
            del old_surface_saved
Answered By: Edward

First, You don’t detect the new window size before redrawing the screen.

Add the get_size() method at line 45 and it works:

#--------------------------------------------------------------
# Draw the grid
size = pygame.display.get_surface().get_size() // size update
for row in range(int(math.ceil(size[1]/height))+1):
#---------------------------------------------------------

Then you work with a fixed cell size (50, 20) and fill as many cells as possible. If You want to GROW/SHRINK the cells when resizing the window, You will have to define the NUMBER of cells per line/row, then calculate the cell size, then draw them.

Answered By: zwitsch

A simple way to do which I found was the following code snippet

# Imports
from vars import *
from pygame.locals import *

# Main init
pygame.init()

# Basic vars
run = True
s_width = 1000
s_height = 600

# Making display screen. Don't forget the last tag!
screen = pygame.display.set_mode((s_width, s_height), RESIZABLE)

# Main loop
while run:
    # event detection
    for event in pygame.event.get():
        if event.type == QUIT:
            run = False
        # The part which matters for our purposes
        if event.type == WINDOWRESIZED:
            s_width, s_height = screen.get_width(), screen.get_height()
        if event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                run = False
    # Test line to see if the window resizing works properly
    pygame.draw.line(screen, (255, 255, 255), (int(0.3*s_width), int(0.25*s_height)), (int(0.8*s_width), int(0.25*s_height)))
    # Final flip
    pygame.display.flip()

# Quit
pygame.quit()

What this does is allows the pygame window to be resized. But since you often have the placing and sizes of a lot of elements/sprites depending on the s_width and s_height, it also detects when the window size is changed and adjusts the dimensions accordingly.

Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.