且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

放大和缩小 PyGame 窗口,所有对象仍然在原位

更新时间:2023-01-24 08:18:51

缩放时需要对原始图像进行缩放和blit.使用属性 maprect 定义地图的缩放大小和相对位置.添加可以缩放和 blit 地图的方法 blit 地图.使用App类的构造函数中的方法:

class 应用:def __init__(self):# [...]self.map = pygame.image.load(imagedir)self.maprect = self.map.get_rect(center = self.window.get_rect().center)self.blitmap()#创建窗口pygame.display.flip()def blitmap(self):self.mapsurface = pygame.transform.smoothscale(self.map, self.maprect.size)self.window.fill(0)self.window.blit(self.mapsurface,self.maprect)# [...]

当图片放大后,计算新的映射矩形(self.maprect)并再次调用该方法:

class 应用:# [...]def check_event(self,event):如果 event.type == pygame.QUIT:self.running = Falseelif event.type == pygame.VIDEORESIZE:self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)self.blitmap()elif event.type == pygame.MOUSEBUTTONDOWN:如果 event.button == 4 或 event.button == 5:zoom = 2 if event.button == 4 else 0.5mx,我的 = event.pos左 = mx + (self.maprect.left - mx) * 缩放右 = mx + (self.maprect.right - mx) * 缩放顶部 = 我的 + (self.maprect.top - 我的) * 缩放底部 = 我的 + (self.maprect.bottom - my) * 缩放self.maprect = pygame.Rect(left, top, right-left, bottom-top)self.blitmap()

另见

导入pygame从 pygame.locals 导入 *导入操作系统类应用程序:def __init__(self):self.running = 真self.size = (800,600)#创建窗口self.window = pygame.display.set_mode(self.size, pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)#创建地图currentdir = os.path.dirname(os.path.realpath(__file__))imagedir = currentdir+'/images/europe.png'self.map = pygame.image.load(imagedir)self.maprect = self.map.get_rect(center = self.window.get_rect().center)self.blitmap()#创建窗口pygame.display.flip()def blitmap(self):self.mapsurface = pygame.transform.smoothscale(self.map, self.maprect.size)self.window.fill(0)self.window.blit(self.mapsurface,self.maprect)def on_init(self):self.country = Country()def on_cleanup(self):pygame.quit()def check_event(self,event):如果 event.type == pygame.QUIT:self.running = Falseelif event.type == pygame.VIDEORESIZE:self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)self.blitmap()elif event.type == pygame.MOUSEBUTTONDOWN:如果 event.button == 4 或 event.button == 5:缩放 = 2 如果 event.button == 4 else 0.5mx,我的 = event.pos左 = mx + (self.maprect.left - mx) * 缩放右 = mx + (self.maprect.right - mx) * 缩放顶部 = 我的 + (self.maprect.top - 我的) * 缩放底部 = 我的 + (self.maprect.bottom - my) * 缩放self.maprect = pygame.Rect(left, top, right-left, bottom-top)self.blitmap()pygame.display.update()def on_execute(self):而 self.running == True:对于 pygame.event.get() 中的事件:self.check_event(事件)self.on_cleanup()类国家(应用程序):def __init__(self):super().__init__()开始 = 应用程序()start.on_init()start.on_execute()

I am having an issue with PyGame i can't resolve. So: my idea is that I have a map I can zoom in/out on. zooming in works fine. But zooming out shows that the rest of the picture got deleted and only the part of the image that was previously visible on the window exists now. This is my code:

import pygame
from pygame.locals import *
import os

class App:
    def __init__(self):
        self.running = True
        self.size = (800,600)

         #create window
        self.window = pygame.display.set_mode(self.size, pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)

        #create map
        currentdir = os.path.dirname(os.path.realpath(__file__))
        imagedir = currentdir+'/images/europe.png'
        self.map =  pygame.image.load(imagedir)
        self.maprect = self.map.get_rect()
        self.mapsurface = pygame.Surface(self.size)
        self.mapsurface.blit(pygame.transform.scale(self.map,(self.size)),(0,0))
        self.window.blit(self.mapsurface,(0,0))
        self.scale = 1

        #create window
        pygame.display.flip()

    def on_init(self):
        self.country = Country()

    def on_cleanup(self):
        pygame.quit()
        
    def check_event(self,event):
        if event.type == pygame.QUIT:
            self.running = False
        elif event.type == pygame.VIDEORESIZE:
            self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
            self.window.blit(pygame.transform.scale(self.map,(event.dict['size'])),(0,0))
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 4:
                zoom = 2
                wnd_w,wnd_h = self.window.get_size()
                zoom_size = (round(wnd_w/zoom), round(wnd_h/zoom))
                zoom_area = pygame.Rect(0,0, *zoom_size)
                pos_x,pos_y = pygame.mouse.get_pos()
                zoom_area.center = (pos_x, pos_y)
                zoom_surf = pygame.Surface(zoom_area.size)
                zoom_surf.blit(self.window, (0, 0), zoom_area)
                zoom_surf = pygame.transform.smoothscale(zoom_surf, (wnd_w, wnd_h))
                self.window.blit(zoom_surf, (0, 0))

            elif event.button == 5:
                zoom = 0.5
                wnd_w,wnd_h = self.window.get_size()
                zoom_size = (round(wnd_w/zoom), round(wnd_h/zoom))
                zoom_area = pygame.Rect(0,0,*zoom_size)
                pos_x,pos_y = pygame.mouse.get_pos()
                zoom_area.center = (pos_x, pos_y)
                zoom_surf = pygame.Surface(zoom_area.size)
                zoom_surf.blit(self.window, (0, 0), zoom_area)
                zoom_surf = pygame.transform.smoothscale(zoom_surf, (wnd_w, wnd_h))
                self.window.blit(zoom_surf, (0, 0))
            pygame.display.flip()

        pygame.display.update()
    def on_execute(self):
        while self.running == True:
            for event in pygame.event.get():
                self.check_event(event)
        self.on_cleanup()

class Country(App):
    def __init__(self):
        super().__init__()
    

start = App()
start.on_init()
start.on_execute()

Here are the screenshots of my problem:

so far so good:

zooming in works fine:

zooming out causes this:

You'll need to scale and blit the original image when you zoom. Use the attribute maprect to define the scaled size and relative location of the map. Add a method blit map that can scale and blit the map. Use the method in the constructor of the class App:

class App:
    def __init__(self):
        # [...]

        self.map =  pygame.image.load(imagedir)
        self.maprect = self.map.get_rect(center = self.window.get_rect().center)
        self.blitmap()

        #create window
        pygame.display.flip()

    def blitmap(self):
        self.mapsurface = pygame.transform.smoothscale(self.map, self.maprect.size)
        self.window.fill(0)
        self.window.blit(self.mapsurface, self.maprect)

    # [...]

When the image is zoomed, calculate the new mapping rectangle (self.maprect) and call the method again:

class App:
    # [...]

    def check_event(self,event):
        if event.type == pygame.QUIT:
            self.running = False

        elif event.type == pygame.VIDEORESIZE:
            self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
            self.blitmap()

        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 4 or event.button == 5:
                zoom = 2 if event.button == 4 else 0.5
                mx, my = event.pos
                left   = mx + (self.maprect.left - mx) * zoom
                right  = mx + (self.maprect.right - mx) * zoom
                top    = my + (self.maprect.top - my) * zoom
                bottom = my + (self.maprect.bottom - my) * zoom
                self.maprect = pygame.Rect(left, top, right-left, bottom-top)
                self.blitmap()

See also Scale and zoom window


Complete example:

import pygame
from pygame.locals import *
import os

class App:
    def __init__(self):
        self.running = True
        self.size = (800,600)

         #create window
        self.window = pygame.display.set_mode(self.size, pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)

        #create map
        currentdir = os.path.dirname(os.path.realpath(__file__))
        imagedir = currentdir+'/images/europe.png'
        self.map =  pygame.image.load(imagedir)
        self.maprect = self.map.get_rect(center = self.window.get_rect().center)
        self.blitmap()
        
        #create window
        pygame.display.flip()

    def blitmap(self):
        self.mapsurface = pygame.transform.smoothscale(self.map, self.maprect.size)
        self.window.fill(0)
        self.window.blit(self.mapsurface, self.maprect)

    def on_init(self):
        self.country = Country()

    def on_cleanup(self):
        pygame.quit()
        
    def check_event(self,event):
        if event.type == pygame.QUIT:
            self.running = False
        
        elif event.type == pygame.VIDEORESIZE:
            self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
            self.blitmap()
        
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 4 or event.button == 5:
                zoom = 2 if event.button == 4 else 0.5
                mx, my = event.pos
                left   = mx + (self.maprect.left - mx) * zoom
                right  = mx + (self.maprect.right - mx) * zoom
                top    = my + (self.maprect.top - my) * zoom
                bottom = my + (self.maprect.bottom - my) * zoom
                self.maprect = pygame.Rect(left, top, right-left, bottom-top)
                self.blitmap()

        pygame.display.update()

    def on_execute(self):
        while self.running == True:
            for event in pygame.event.get():
                self.check_event(event)
        self.on_cleanup()

class Country(App):
    def __init__(self):
        super().__init__()
    

start = App()
start.on_init()
start.on_execute()