#button #pygame
#кнопка #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,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()
Ответ №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
После этих изменений ваш скрипт запускается нормально, прежде чем перейти во внешний цикл при нажатии кнопки. Внешний цикл также не обрабатывает выход должным образом, но, вероятно, это просто тот же набор изменений снова и снова.
Было бы лучше иметь только один цикл обработки пользовательского ввода. наличие этих отдельных циклов событий вызывает одну и ту же проблему в нескольких местах. Разработайте способ создания единой функции обработки событий, а затем адаптируйте свой код пользовательского интерфейса для ее использования. Это упростит написание и отладку вашего кода в будущем.
Ссылка: весь код
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()