最近我一直在使用派克模块制作游戏。我注意到Pygame没有内置的GUI元素。为了节省我(希望其他人)的时间,我创建了一些非常简单的GUI元素:按钮和标签。
按钮模块是第一个被创建的,并且可能是最彻底的测试。按钮模块有一个按钮类。类有创建和更新按钮的主要方法。__init__方法、render_button方法和update_button方法。
我在所有方法上都包含了文档字符串,所以我不需要过多地解释代码:
import pygame as pg
pg.init()
class Button:
def __init__(self, surface, x, y, width, height):
"""
Creates a Button that can be used in any pygame project.
Arguments:
surface -- a pygame.display.set_mode() object.
x -- the x axis position of the button's top left corner
y -- the y axis position of the button's top left corner
width -- the width of the button
height -- the height og the button
the syntax of creating a instance of the class:
btn_obj = Button(surface, x, y, width, height)
To display the button and update the button, acording the the mouse
position, two methods must be called:
btn_obj.render_button() -- this method is used to render the button.
Call the function after Updating the pygame screen in your
Pygame window event loop.
btn_obj.update_button() -- this method is used to change the buttons
sytle and to run a specifed function, depending on the mouse position.
Call this function in your Pygame window event loop.
"""
# getting surface/window/display reference
self.surface = surface
# setting button dimensions
self.x = x
self.y = y
self.width = width
self.height = height
# button rectangle and button outline
self.button_obj = pg.Rect(x, y, width, height)
self.button_inline = (self.button_obj[0] - 1, self.button_obj[1] - 1,
self.button_obj[2], self.button_obj[3] + 1)
self.button_outline = (self.button_obj[0] + 1, self.button_obj[1] + 1,
self.button_obj[2] + 1, self.button_obj[3] + 1)
# variables to check if the button is is non-active, active, or pressed
self.normal = True
self.active = False
self.run_function = False
self.clicked = False
# colors for normal button and active button
self.button_color = (210, 210, 210)
self.active_color = (230, 230, 230)
self.pressed_color = (200, 200, 200)
# function for button
self.function = None
# setting default font parameters
self.fs = 18
self.fc = (0, 0, 0)
self.font_name = pg.font.match_font('arial')
self.caption = ""
# setting parameters for button outline and inline color
self.olc = (0, 0, 0)
self.ilc = (255, 255, 255)
def decorate(self, caption="", button_color=(210, 210, 210),
active_color=(230, 230, 230), pressed_color=(200, 200, 200),
font_size=16, font_color=(0, 0, 0),
font_name=pg.font.match_font('arial'),
function=None):
'''
Gives the user the abiltiy to decorate their buttons.
Takes the keyword values given, and changes the
default values accordingly.
Keyword arguments:
caption -- the text(if any) to display on the button.
button_color -- the main color of the button.
actvie_color -- the color of the button when being hovered over.
pressed_color -- the color of the button when being pressed.
font_size -- the size of the button text.
font_color -- the color of the button text.
font_name -- the type/name of font used for displaying button text.
function -- the function to run when the buttons is pressed
'''
self.button_color = self.button_color
self.active_color = self.active_color
self.pressed_color = self.pressed_color
self.function = function
self.fs = font_size
self.fc = font_color
self.font_name = font_name
self.caption = caption
def _set_button_state_pressed(self):
"""
Sets the Button 'click' effect when pressed,
by offsetting the outline and inline lines of the button
"""
self.button_outline = (self.button_obj[0] - 1, self.button_obj[1] - 1,
self.button_obj[2] + 2, self.button_obj[3] + 1)
self.button_inline = (self.button_obj[0] + 1, self.button_obj[1] + 1,
self.button_obj[2], self.button_obj[3])
def _set_button_state_normal(self):
"""
Sets the Button state to normal when not being clicked
by resetting the outline and inline lines of the button
"""
self.button_inline = (self.button_obj[0] - 1, self.button_obj[1] - 1,
self.button_obj[2] + 1, self.button_obj[3] + 1)
self.button_outline = (self.button_obj[0] - 1, self.button_obj[1] - 1,
self.button_obj[2] + 3, self.button_obj[3] + 3)
def _draw_button_text(self):
"""
Creates the Button text to draw on the button.
Changes the button text position text, when the
button is being clicked
"""
if self.clicked:
self.font = pg.font.Font(self.font_name, self.fs)
self.font_surf = self.font.render(self.caption, True, self.fc)
w, h = self.font.size(self.caption)
self.font_pos = (self.x + self.width / 2 - w / 2 + 1, self.y + self.height / 2 - h / 2 + 1) # I'm adding +1
# to the text position when pressed to move the text with the button
self.surface.blit(self.font_surf, self.font_pos)
else:
self.font = pg.font.Font(self.font_name, self.fs)
self.font_surf = self.font.render(self.caption, True, self.fc)
w, h = self.font.size(self.caption)
self.font_pos = (self.x + self.width / 2 - w / 2 - 1, self.y + self.height / 2 - h / 2 - 1)
self.surface.blit(self.font_surf, self.font_pos)
def render_button(self):
"""
Renders the button to the screen while checking for
each button state flag(self.normal, self.active, self.pressed)
"""
if self.clicked:
self._set_button_state_pressed()
pg.draw.rect(self.surface, self.olc, self.button_outline)
pg.draw.rect(self.surface, self.ilc, self.button_inline)
pg.draw.rect(self.surface, self.button_color, self.button_obj)
else:
self._set_button_state_normal()
pg.draw.rect(self.surface, self.olc, self.button_outline)
pg.draw.rect(self.surface, self.ilc, self.button_inline)
pg.draw.rect(self.surface, self.button_color, self.button_obj)
# change button color based on the event(active, pressed, or normal)
if self.active and not self.clicked:
pg.draw.rect(self.surface, self.active_color, self.button_obj)
elif self.clicked and self.active:
pg.draw.rect(self.surface, self.pressed_color, self.button_obj)
elif self.normal:
pg.draw.rect(self.surface, self.button_color, self.button_obj)
self._draw_button_text()
def _update(self, event):
"""
Sets the self.active flag and the self.pressed flag
to True at the correct times
"""
x, y = event.pos
mouse_buttons = pg.mouse.get_pressed()
self.active = False
if self.x < x < self.x + self.width:
if self.y < y < self.y + self.height:
self.active = True
if mouse_buttons[0] == 1:
self.active = False
def _mouse_down(self):
"""
sets the flag self.clicked to True when being pressed
"""
if self.active:
self.run_function = True
self.clicked = True
def _mouse_up(self):
"""
checks if the user gives a function for self.function, if they do, then it will be ran
when the button is clicked.
self.run_function is used to track if the button was pressed, like self.clicked.
however self.clicked is used to set the drawing position of the button and thus
has to be set back to false on the MOUSEBUTTONUP event. so a seconds variable(self.run_function)
is needed to know when to run the function given. When the function is run, self.run_function
is set to False until the button is cliked agian which will set it back to True.
"""
self.clicked = False
if self.function is not None and self.active and self.run_function:
self.run_function = False
self.function()
elif self.function is None and self.active is True and self.run_function:
self.run_function = False
def update_button(self, event_object):
"""
checks for the actual pygame events, and calls the right function accordingly
"""
if event_object.type == pg.MOUSEBUTTONDOWN and self.active is True:
self._mouse_down()
if event_object.type == pg.MOUSEBUTTONUP:
self._mouse_up()
if event_object.type == pg.MOUSEMOTION:
self._update(event_object)
def is_clicked(self):
"""
Checks if the button was pressed for the user.
and returns True if it was. Use the method in
a if-statement, to test if the buttons is\was
pressed:
if btn_obj.is_clicked:
.....
"""
if self.clicked is True:
return True
else:
return False我在上面的代码中讨论的唯一问题是,我是否应该有一个单独的方法(decorate)来设置按钮的样式,还是应该让用户在__init__方法中这样做。
标签模块要简单得多,代码也少得多。label模块有一个名为Label的类。与按钮类一样,label类具有__init__、render和update方法:
import pygame as pg
pg.init()
class Label:
def __init__(self, surface, x, y, w, h,
color=(230, 230, 230),
label_highlight=(False, (255, 255, 255)), text="",
text_pos=(0, 0), font_size=18,
font_type=pg.font.match_font('arial'),
font_color=(0, 0, 0)):
'''
A multipurpose label object for pygame games.
Arguments:
surface -- your pygame.display.set_mode() object.
x -- the x axis position of the labels's top left corner
y -- the y axis position of the labels's top left corner
width -- the width of the button
height -- the height of the button
Keyword arguments:
color -- main color of the label(default: white)
label_highlight -- takes a boolean and a color. If you entered
True, the label will b highlighted the color you
specify(default: False (255, 255, 255))
text -- text to display on label(default: "")
text_pos -- the x and y coordinates of the text
realative to your label(default: (0, 0))
font_size -- size of label font(default: 18)
font_type -- type of font to use for label font(default: arial)
font_color -- color of font displayed on label(default: (0, 0, 0))
the syntax of creating a instance of the class:
lbl_obj = Label(surface, x, y, width, height)
To display the label and update the label, acording the the mouse
position, two methods must be called:
lbl_obj.render_label() -- this method is used to render the label.
Call the function after Updating the pygame screen in your
Pygame window event loop.
lbl_obj.update_label() -- this method is used to change the labels
color depending on the mouse position.
Call this function in your Pygame window event loop.
'''
self.surface = surface
self.x = x
self.y = y
self.w = w
self.h = h
self.tp = text_pos
self.fs = font_size
self.ft = font_type
self.fc = font_color
self.hovering = False
######--------------------#######
self.label = pg.Surface((self.w, self.h))
self.label_color = color
self.label_pos = (self.x, self.y)
self.label.fill(self.label_color)
self.label_highlight = label_highlight[0]
self.label_highlight_color = label_highlight[1]
self.text = text
def _render_text(self):
''' Used to render the label text'''
self.font = pg.font.Font(self.ft, self.fs)
w, h = self.font.size(self.text)
self.font_surf = self.font.render(self.text, True, self.fc)
self.label.blit(self.font_surf, (self.tp[0], self.tp[1]))
def render_label(self):
''' Used to render the label'''
if self.hovering:
self.label.fill(self.label_highlight_color)
self._render_text()
self.surface.blit(self.label, self.label_pos)
elif not self.hovering:
self.label.fill(self.label_color)
self._render_text()
self.surface.blit(self.label, self.label_pos)
def _update(self, event_obj):
''' This function is only called if the user sets
label_hightlight equal to True and gives a color.
'''
x, y = event_obj.pos
self.hovering = False
if x > self.x and x < self.x + self.w:
if y > self.y and y < self.y + self.h:
self.hovering = True
def update_label(self, event_obj):
''' Calls the acutal Pygame events to update the label'''
if event_obj.type == pg.MOUSEMOTION:
if self.label_highlight:
self._update(event_obj)
print(self.hovering)我想知道的主要批评是:
下面是一个使用每个模块的示例。只需确保按钮和标签模块位于同一个目录中。然后复制粘贴:
import pygame as pg
import button
import label
pg.init()
WIDTH = 800
HEIGHT = 600
display = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption("Test of GUI elemnts")
clock = pg.time.Clock()
btn = button.Button(display, 300, 300, 100, 20)
lbl = label.Label(display, 300, 270, 100, 20, text="Btn 1")
btn.decorate(caption="btn1")
running = True
while running:
clock.tick(60)
for e in pg.event.get():
if e.type == pg.QUIT:
running = False
pg.quit()
quit()
btn.update_button(e)
lbl.update_label(e)
display.fill((200, 200, 200))
btn.render_button()
lbl.render_label()
pg.display.update()发布于 2016-08-21 06:45:20
您意识到,当调用.decorate方法时,会重置任何未设置的参数?所以如果我打电话:
button.decorate(caption='mycaption')
button.decorate(font_size=32)那么第二个调用将标题重置为""?
另外,还有其他的游戏GUI图书馆,所以在重新发明轮子之前,您可能会检查那里。
https://codereview.stackexchange.com/questions/138810
复制相似问题