【问题标题】:Creating Buttons in PyGame在 PyGame 中创建按钮
【发布时间】:2020-11-12 10:32:52
【问题描述】:

我正在为一个自动时间表制作一个程序,并且我已经设法创建了一个标题,但我想添加一个登录和注册按钮,该按钮进入一个新页面。我还想在这些新页面上添加一个返回按钮。我正在使用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,0)

def create_surface_with_text(text, font_size, text_rgb, bg_rgb):

    font = pygame.freetype.SysFont("Arial", font_size, 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, font_size, bg_rgb, text_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, text_rgb=text_rgb, 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),
        font_size=30,
        bg_rgb=WHITE,
        text_rgb=BLACK,
        text="Log In",
        action=GameState.LOGIN,
    )

    uielement = UIElement(
        center_position=(400, 100),
        font_size=40,
        bg_rgb=PINK,
        text_rgb=BLACK,
        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,

        bg_rgb=WHITE,

        text_rgb=BLACK,

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

【问题讨论】:

    标签: button pygame


    【解决方案1】:

    对于初学者来说,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,0)
    
    def create_surface_with_text(text, font_size, text_rgb, bg_rgb):
    
        font = pygame.freetype.SysFont("Arial", font_size, 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, font_size, bg_rgb, text_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, text_rgb=text_rgb, 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):
            """ 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
    
    
        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),
            font_size=30,
            bg_rgb=WHITE,
            text_rgb=BLACK,
            text="Log In",
            action=GameState.LOGIN,
        )
    
        uielement = UIElement(
            center_position=(400, 100),
            font_size=40,
            bg_rgb=PINK,
            text_rgb=BLACK,
            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,
            bg_rgb=WHITE,
            text_rgb=BLACK,
            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() 
    

    【讨论】:

      猜你喜欢
      • 2016-04-27
      • 2015-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-20
      • 1970-01-01
      相关资源
      最近更新 更多