问题
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:
回答1:
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()
来源:https://stackoverflow.com/questions/64936805/zooming-in-and-out-of-a-pygame-window-with-all-objects-still-in-place