允许改变大小的pyGame窗口

29

我试图让这个应用程序可以调整大小,我添加了RESIZABLE标志,但是当我尝试调整大小时,它会出现问题!请试试我的代码。

这是一个网格程序,当窗口大小调整时,我希望网格也能够随之调整/缩小。

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 ()

请告诉我出了什么问题,谢谢。

5个回答

23

解决这个问题(允许Pygame窗口和其中的表面调整大小)的答案就是,在用户更改其尺寸时(在pygame.VIDEORESIZE事件上完成),简单地使用更新后的尺寸重新创建可调整大小的窗口即可。

>>> 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
>>> 

这会清除窗口表面上的所有先前内容,因此在下面
有一个过程来继续当前窗口的内容。

一些示例代码:

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)

如何继续使用当前窗口内容:
以下是添加回先前窗口内容的步骤:

  1. 创建第二个变量,并将其设置为旧窗口表面变量的值。
  2. 创建新窗口,将其存储为旧变量。
  3. 使用blit函数,将第二个表面绘制到第一个表面(旧变量)上。
  4. 使用此变量并删除新变量(可选,使用del),以免使用额外的内存。

以下是上述步骤的一些示例代码(替换了pygame.VIDEORESIZE事件的if语句):

        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

当我运行上面的示例后,经过第一秒钟窗口停止正确绘制调整大小的矩形在中心。 - Ivan Kovtun
1
我发现了这个pygame的开放性问题。简而言之:通过移动边缘调整大小可以发送VIDEORESIZE事件,但尝试移动角落后会失败。 - Ivan Kovtun

14

2

一个简单的可调整大小的Hello World窗口,同时我正在尝试使用类进行操作。
拆分成两个文件,一个用于定义颜色常量。

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)

14
代码可运行,但您应该阅读PEP 8风格指南。您使用的名称违反了许多约定,例如CreateWindow不是一个类,helloWorld是一个类,DISPLAYSURF不是常量。此外,请避免在各处滥用“from ... import *”,特别是因为您并未使用它们(您无论如何都会添加前缀来调用 pygame)。 - MestreLion
@MestreLion,from pygame.locals import * 是为了 QUITRESIZEABLEVIDEORESIZE。pygame 调用不是该导入的一部分... 我已经提交了一个编辑,但是可能您实际上正在查看此示例的早期版本,该版本导入 pygame 的方式有所不同。 - Ryan Beesley

1
我发现一个简单的方法是使用以下代码片段:
# 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()

这样做可以允许pygame窗口调整大小。但由于很多元素/精灵的位置和大小都取决于s_width和s_height,因此它还会检测窗口大小是否更改并相应地调整尺寸。

0
首先,在重新绘制屏幕之前,您没有检测新窗口大小。
在第45行添加get_size()方法即可解决:
#--------------------------------------------------------------
# Draw the grid
size = pygame.display.get_surface().get_size() // size update
for row in range(int(math.ceil(size[1]/height))+1):
#---------------------------------------------------------

然后,您可以使用固定的单元格大小(50,20),并填充尽可能多的单元格。如果您想要在调整窗口大小时增大/缩小单元格,则必须定义每行/列的单元格数量,然后计算单元格大小,最后绘制它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接