如何解决在PyGame中创建按钮
我正在制作一个用于自动时间表的程序,我设法创建了一个标题,但是我想添加一个登录页面并注册一个进入新页面的按钮。我还想在这些新页面上添加一个返回按钮。我当时正在使用programmingpixels.com来提供帮助,但是我仍然无法做我想做的事。我是使用PyGame的新手,所以我可能没有完成高效的代码,可能会出现很多错误。我的标题屏幕以前可以正常工作,但是当我尝试添加这些按钮时,它是空白的,不会让我退出屏幕。任何帮助都会很棒。谢谢。
import pygame
import pygame.freetype
from pygame.sprite import Sprite
from pygame.rect import Rect
from enum import Enum
PINK = (250,100,100)
WHITE = (255,255,255)
BLACK = (0,0)
def create_surface_with_text(text,font_size,text_rgb,bg_rgb):
font = pygame.freetype.SysFont("Arial",bold=True)
surface,_ = font.render(text=text,fgcolor=text_rgb,bgcolor=bg_rgb)
return surface.convert_alpha()
class UIElement(Sprite):
def __init__(self,center_position,text,bg_rgb,action=None):
self.mouse_over = False
# what happens when the mouse is not over the element
default_image = create_surface_with_text(
text=text,font_size=font_size,text_rgb=text_rgb,bg_rgb=bg_rgb
)
# what happens when the mouse is over the element
highlighted_image = create_surface_with_text(
text=text,font_size=font_size * 1.1,bg_rgb=bg_rgb
)
self.images = [default_image,highlighted_image]
self.rects = [
default_image.get_rect(center=center_position),highlighted_image.get_rect(center=center_position),]
self.action = action
super().__init__()
@property
def image(self):
return self.images[1] if self.mouse_over else self.images[0]
@property
def rect(self):
return self.rects[1] if self.mouse_over else self.rects[0]
def update(self,mouse_pos,mouse_up):
if self.rect.collidepoint(mouse_pos):
self.mouse_over = True
else:
self.mouse_over = False
def draw(self,surface):
surface.blit(self.image,self.rect)
def main():
pygame.init()
screen = pygame.display.set_mode((800,600))
game_state = GameState.LOGIN
while True:
if game_state == GameState.LOGIN:
game_state = log_in(screen)
if game_state == GameState.SIGNUP:
game_state = sign_up(screen)
if game_state == GameState.RETURN:
game_state = title_screen(screen)
if game_state == GameState.QUIT:
pygame.quit()
return
def title_screen(screen):
login_btn = UIElement(
center_position=(400,300),font_size=30,bg_rgb=WHITE,text_rgb=BLACK,text="Log In",action=GameState.LOGIN,)
signup_btn = UIElement(
center_position=(400,200),)
uielement = UIElement(
center_position=(400,100),font_size=40,bg_rgb=PINK,text="Welcome to the Automated TiMetable Program",action=GameState.QUIT,)
buttons = [login_btn,signup_btn]
while True:
mouse_up = False
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
mouse_up = True
elif event.type == pygame.QUIT:
pygame.quit()
sys.exitIO
screen.fill(PINK)
for button in buttons:
ui_action = button.update(pygame.mouse.get_pos(),mouse_up)
if ui_action is not None:
return ui_action
button.draw(screen)
pygame.display.flip()
def log_in(screen):
return_btn = UIElement(
center_position=(140,570),font_size=20,text="Return to main menu",action=GameState.TITLE,)
while True:
mouse_up = False
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
mouse_up = True
screen.fill(PINK)
ui_action = return_btn.update(pygame.mouse.get_pos(),mouse_up)
if ui_action is not None:
return ui_action
return_btn.draw(screen)
pygame.display.flip()
class GameState(Enum):
LOGIN = -1
SIGNUP = 0
RETURN = 1
QUIT = 2
if __name__ == "__main__":
main()
解决方法
对于初学者,GameState
缺少TITLE
值。
class GameState(Enum):
# ...
TITLE = 3
添加此代码可使代码运行。
log_in()
函数无法处理正在关闭的窗口。在每个事件循环中,您必须处理pygame.QUIT
事件。例如:
def log_in( screen ):
# ...
while True:
mouse_up = False
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
pygame.event.post( pygame.event.Event( pygame.QUIT ) ) # re-send the quit event to the next loop
return GameState.QUIT
elif ( event.type == pygame.MOUSEBUTTONUP and event.button == 1 ):
mouse_up = True # Mouse button 1 weas released
ui_action = return_btn.update( pygame.mouse.get_pos(),mouse_up )
if ui_action is not None:
print( "log_in() - returning action" )
return ui_action
screen.fill(PINK)
return_btn.draw(screen)
pygame.display.flip()
当在控件上释放鼠标按钮时,UIElement.update()
看起来应该返回self.action
。但是,在现有代码中,什么也不会返回。可能需要这样:
class UIElement( Sprite ):
# ...
def update(self,mouse_pos,mouse_up):
""" Track the mouse,setting the self.mouse_over. Also check
if the mouse-button was clicked while over this control
returning the pre-defined self.action,if so. """
result = None # No click => no action
if self.rect.collidepoint(mouse_pos):
self.mouse_over = True
if ( mouse_up ):
result = self.action # Mouse was clicked on element,add action
else:
self.mouse_over = False
return result
这些更改之后,您的脚本运行正常,然后在单击按钮时进入外部循环。外循环也不能正确处理退出,但可能只是同一组更改而已。
最好只有一个用户输入处理循环。具有这些单独的事件循环会在多个位置导致相同的问题。找出一种具有单个事件处理功能的方法,然后修改您的UI代码以使用它。这将使您的代码更容易编写和调试。
参考:所有代码
import pygame
import pygame.freetype
from pygame.sprite import Sprite
from pygame.rect import Rect
from enum import Enum
PINK = (250,100,100)
WHITE = (255,255,255)
BLACK = (0,0)
def create_surface_with_text(text,font_size,text_rgb,bg_rgb):
font = pygame.freetype.SysFont("Arial",bold=True)
surface,_ = font.render(text=text,fgcolor=text_rgb,bgcolor=bg_rgb)
return surface.convert_alpha()
class UIElement(Sprite):
def __init__(self,center_position,text,bg_rgb,action=None):
self.mouse_over = False
# what happens when the mouse is not over the element
default_image = create_surface_with_text(
text=text,font_size=font_size,text_rgb=text_rgb,bg_rgb=bg_rgb
)
# what happens when the mouse is over the element
highlighted_image = create_surface_with_text(
text=text,font_size=font_size * 1.1,bg_rgb=bg_rgb
)
self.images = [default_image,highlighted_image]
self.rects = [
default_image.get_rect(center=center_position),highlighted_image.get_rect(center=center_position),]
self.action = action
super().__init__()
@property
def image(self):
return self.images[1] if self.mouse_over else self.images[0]
@property
def rect(self):
return self.rects[1] if self.mouse_over else self.rects[0]
def update(self,add action
else:
self.mouse_over = False
return result
def draw(self,surface):
surface.blit(self.image,self.rect)
def main():
pygame.init()
screen = pygame.display.set_mode((800,600))
game_state = GameState.LOGIN
while True:
if game_state == GameState.LOGIN:
game_state = log_in(screen)
if game_state == GameState.SIGNUP:
game_state = sign_up(screen)
if game_state == GameState.RETURN:
game_state = title_screen(screen)
if game_state == GameState.QUIT:
pygame.quit()
return
def title_screen(screen):
login_btn = UIElement(
center_position=(400,300),font_size=30,bg_rgb=WHITE,text_rgb=BLACK,text="Log In",action=GameState.LOGIN,)
signup_btn = UIElement(
center_position=(400,200),)
uielement = UIElement(
center_position=(400,100),font_size=40,bg_rgb=PINK,text="Welcome to the Automated Timetable Program",action=GameState.QUIT,)
buttons = [login_btn,signup_btn]
while True:
mouse_up = False
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
mouse_up = True
elif event.type == pygame.QUIT:
pygame.quit()
sys.exitIO
screen.fill(PINK)
for button in buttons:
ui_action = button.update(pygame.mouse.get_pos(),mouse_up)
if ui_action is not None:
return ui_action
button.draw(screen)
pygame.display.flip()
def log_in(screen):
return_btn = UIElement(
center_position=(140,570),font_size=20,text="Return to main menu",action=GameState.TITLE,)
while True:
mouse_up = False
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
pygame.event.post( pygame.event.Event( pygame.QUIT ) ) # re-send the quit event to the next loop
return GameState.QUIT
elif ( event.type == pygame.MOUSEBUTTONUP and event.button == 1 ):
mouse_up = True # Mouse button 1 weas released
ui_action = return_btn.update( pygame.mouse.get_pos(),mouse_up )
if ui_action is not None:
print( "log_in() - returning action" )
return ui_action
screen.fill(PINK)
return_btn.draw(screen)
pygame.display.flip()
class GameState(Enum):
LOGIN = -1
SIGNUP = 0
RETURN = 1
QUIT = 2
TITLE=3
if __name__ == "__main__":
main()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。