import pygame
from pygame.locals import *
from pygameGUI.error import UIError
from pygameGUI.group import Group, BottomGroup
class Widget:
"""组件基类"""
# states控件状态表
NORMAL = 0 # 正常
HOVER = 1 # 激活
PRESSED = 2 # 按下
def __init__(self, group):
"""自动加入group组"""
# 自身组件交互状态
self.states = self.NORMAL
# 自身矩形位置(默认
self.rect = pygame.Rect([0, 0, 0, 0])
# 属于的组
self.group = group
if type(group) is BottomGroup: # 是底层组
self.group = group
self.group.add(self)
elif isinstance(self.group, Frame):
self.group = group.group # 是Frame大类
self.master = group
self.group.add(self)
else:
raise UIError("group参数应该是一个Frame类")
def update(self, *args, **kwargs):
"""每帧调用"""
return
def draw(self, screen):
"""每帧绘制"""
pass
def get_rect(self):
"""获取组件在最底层surface对象中的矩形位置(帝龟)"""
if hasattr(self, "master"):
rect = [self.rect[0] + self.master.get_rect()[0],
self.rect[1] + self.master.get_rect()[1],
self.rect[2],
self.rect[3]]
return pygame.Rect(rect)
else:
screen_rect = self.group.screen.get_rect()
rect = [screen_rect[0] + self.rect[0],
screen_rect[1] + self.rect[1],
self.rect[2],
self.rect[3]]
return pygame.Rect(rect)
@staticmethod
def draw_texture(texture, size):
"""绘制纹理"""
image = pygame.Surface(size, pygame.SRCALPHA)
if type(texture) is tuple or type(texture) is list:
image.fill(texture)
elif callable(texture):
image = texture(image)
elif type(texture) is pygame.Surface:
image = texture
else:
raise UIError("texture的类型应该是一个元组/列表、返回image函数 或 一个Surface对象")
return image
@staticmethod
def replace_rect(rect, image):
"""在改变纹理后刷新矩形位置
| rect : 原位置
| image : 新图片
~ 新位置中心点设为与原位置的中心点重合"""
x, y = rect.center
rect = image.get_rect()
rect.center = x, y
return rect
@staticmethod
def default_rect_detection(widget, *args, **kwargs):
if (not BottomGroup.block or widget.unblock) \
and widget.get_rect().collidepoint(kwargs["pos"]):
# 开启阻断
if widget.block is True:
BottomGroup.block = True
return widget.HOVER
else:
return widget.NORMAL
class Frame(Widget):
"""框架结构"""
def __init__(self, group, pos=(0, 0), size=(100, 100), texture=(0, 0, 0), block=True, unblock=False):
super().__init__(group)
# 阻断与阻断免疫
self.block = block
self.unblock = unblock
# 默认交互检测
self.detection = super().default_rect_detection
# 默认控制行为
def command(states, *args, **kwargs):
if states == self.HOVER:
pass
self.states = states
self.command = command
# 生成图像和纹理
self.image = self.draw_texture(texture, size)
# 设置矩形
self.rect = self.image.get_rect()
self.rect.x, self.rect.y = pos
# 内置组
self.widgets = Group(self)
def update(self, *args, **kwargs):
"""刷新"""
# 刷新内部组的组件
self.widgets.update(*args, **kwargs)
# 判定
states = self.detection(self, *args, **kwargs)
# 执行交互行为
self.command(states)
def draw(self, surface):
"""绘制"""
image = self.image.copy()
self.widgets.draw(image)
surface.blit(image, [self.rect.x, self.rect.y])
def set_image(self, size=(100, 100), texture=(0, 0, 0)):
"""设置图片,自动将新图片的中心与就图片中心重合"""
self.image = self.draw_texture(texture, size)
self.rect = self.replace_rect(self.rect, self.image)
def delete(self):
self.group.widgets.remove(self)
class Button(Widget):
def __init__(self, group, pos=(0, 0), size=(50, 25), texture=(230, 230, 230),
block=True, unblock=False):
super().__init__(group)
# 阻断与阻断免疫
self.block = block
self.unblock = unblock
# 生成图像和纹理
self.image = self.draw_texture(texture, size)
# 设置矩形
self.rect = self.image.get_rect()
self.rect.x, self.rect.y = pos
# 默认的交互检测
def detection(widget, *args, **kwargs):
if widget.default_rect_detection(widget, *args, **kwargs):
# 判断输出交互状态
if pygame.mouse.get_pressed()[0]:
return widget.PRESSED
else:
return widget.HOVER
else:
return widget.NORMAL
self.detection = detection
# 默认控制行为
def command(states, *args, **kwargs):
if states == self.NORMAL: # 正常
self.set_image()
elif states == self.HOVER: # 交互状态
self.set_image(texture=(240, 240, 240))
if self.states == self.PRESSED: # 从按下状态返回交互状态
print("按钮完成了一次点击")
elif states == self.PRESSED: # 按下状态
self.set_image(texture=(220, 220, 220))
self.states = states
self.command = command
def update(self, *args, **kwargs):
"""刷新"""
# 判定
states = self.detection(self, *args, **kwargs)
# 执行交互行为
self.command(states)
def draw(self, surface):
"""绘制"""
surface.blit(self.image, [self.rect.x, self.rect.y])
def set_image(self, size=(50, 25), texture=(230, 230, 230)):
"""设置图片,自动将新图片的中心与就图片中心重合"""
self.image = self.draw_texture(texture, size)
self.rect = self.replace_rect(self.rect, self.image)