【pygameGUI 1.0】教程 —— 【已完结】 8/17
本帖最后由 cjjJasonchen 于 2023-8-22 13:32 编辑pygameGUI教程
前言:
大家都知道,pygame哪里都好,就是用起来太麻烦了,控件什么的甚至完全没有。。。{:10_282:}
于是这次我写了一个专门用来给pygame写gui的库{:10_297:}
源代码:源码及简单演示
首先,阅读本教程之前,请你确保自己有一定的python基础,
并且能够熟练至少会背游戏最小循环的使用pygame。
这次我写了三个组件供玩家使用:Label、Button、Frame
Label:生成简单的单行文本,可以作为参数传给Button作为Button上显示的文字
内部的文本可以在创建之后通过 set() 方法多次改变
Button:一个简单的按钮,拥有普通、选中(鼠标位于上方)、按下(鼠标点击)三种状态,
被完成一次单机后(鼠标在按钮上按下,并且在按钮上松开)会调用command中的函数,
command中的函数暂时不支持传入参数
Frame: 一个简单的框架结构,你可以将Label组件和Button放在上面,以便于设定位置,
此组件还有一个正在实验的用法:生成一个窗口,
但是目前这个窗口没有阻塞控制和阻断其他进程的效果,点击窗口中的部件可能会导致触发被窗口遮盖的部件
pygameGUI最小循环
首先,掏出珍藏已久的pygame框架:作者使用的pygame框架
把pygameGUI和放在同一目录下:
导入库:
import pygame
import sys
import pygameGUI as pgui
from pygame.locals import *
创建gui组:guis = pgui.Group()
在主循环的开头添加:
pos = pygame.mouse.get_pos()
rel = pygame.mouse.get_rel()
得到鼠标实时位置和移动
在61行“#鼠标”处,修改:
# 鼠标
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
guis.press()
if event.type == MOUSEBUTTONUP:
if event.button == 1:
guis.release()
guis会通过自动获取位置来得知你单击的是哪个组件
在第84行及之后的改为:
guis.move()
#画背景
screen.fill(bg_color)
# 刷新guis
guis.update(pos,rel)
# 画guis
guis.draw(screen)
# 刷新界面
pygame.display.update()
移动所有被拖动的组件,然后刷新,绘制
好的,看看完整代码~
import pygame
import sys
import pygameGUI as pgui
from pygame.locals import *
# 颜色常量
WHITE = (255,255,255)
BLACK = (0,0,0)
size = width, height = 800,600
screen = pygame.display.set_mode(size)
pygame.display.set_caption("pygame-GUI-Label")
guis = pgui.Group()
clock = pygame.time.Clock()
delay = 60 # 延时计时器(1秒)
# 是否全屏
fullscreen = False
screen_change = False
# 背景颜色设定
bg_color = WHITE
running = True
while running:
pos = pygame.mouse.get_pos()
rel = pygame.mouse.get_rel()
# 设定帧数
clock.tick(60)
# 延时计时器刷新
if delay == 0:
delay = 60
delay -= 1
# 检测是否全屏
if fullscreen and screen_change:
screen = pygame.display.set_mode(size,FULLSCREEN,HWSURFACE)
screen_change = False
elif screen_change:
screen = pygame.display.set_mode(size)
screen_change = False
# 事件检测
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# 鼠标
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
guis.press()
if event.type == MOUSEBUTTONUP:
if event.button == 1:
guis.release()
# 按键按下事件
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
#F11切换全屏
if event.key == K_F11:
fullscreen = not fullscreen
screen_change = True
# 按键抬起事件
if event.type == KEYUP:
pass
guis.move()
#画背景
screen.fill(bg_color)
# 刷新guis
guis.update(pos,rel)
# 画guis
guis.draw(screen)
# 刷新界面
pygame.display.update()
variablepygameGUI专用变量对象
通常,Variable被用来接受Button组件中Command的返回值
Variable
__init__(value=None)
value 可以是各种python的变量
get()
返回变量的值
set(value)
设置变量的值
value 可以是各种python的变量
UI类
UI(pygame.sprite.Sprite)
一些每个ui组件都要具备的方法和调用时机
def press(self,pos):
"鼠标按下时调用"
pass
def release(self,pos):
"鼠标松开时调用"
pass
def move(self,rel):
"每帧调用,被拖动的组件判断是否需要移动"
pass
set_pos(location="center",position=)
这是一种更高级的设置位置的方法,可以让你更方便的设置组件的位置
location:
"center"设置中心位置
"right" 设置左侧位置
"left" 设置右侧位置
"top" 设置顶部位置
"bottom"设置底部位置
pos:
当location为"center"时,接受一个列表或者元组,
其他时候都只接受int
Label 单行文本
Label (master=None, pos=,text=" ",font=(None,15),antialias=True,color=,background=None,alpha=255)
master : 该对象绘制的对象(跟随移动,而不是真的绘制在上面),如果None就是绘制在screen上 -> Frame
pos : 左上角位置 ->
text : 文本 -> str
font : 字体和字号 -> (字体(.ttf文件),字号(int))
antialias : 抗锯齿 -> bool
color : 字体颜色 -> (RGB)
background : 背景颜色 -> (RGB) None表示透明
alpha : 透明度 -> int 0到255
方法:
set_text (text)
text : 新的文本 -> str
set_pos : 更多设置位置的方法 ————> 见上方 ”基础知识-UI类“
举个例子{:10_271:}
我们先从最简单的出发:
在创建guis组后面,打上
# 生成控件
l = pgui.Label(text="I am Label!")
guis.add(l)
然后就可以看到
怎么样!是不是非常简单!是不是非常方便!
然后我们加一点点自定义:
# 生成控件
l = pgui.Label(
text="I am Label!",
pos=,
font=("和音体.ttf",30),
color=(0,200,180),
)
然后就可以看到
设置一下颜色,改一下大小字体和位置,一下子就变得美观啦!
设置一下背景试试:
l = pgui.Label(
text="I am Label!",
pos=,
font=("和音体.ttf",30),
color=(100,255,200),
background=(255,255,200)
)
然后就可以看到
这个组件是不是比原版的font用起来舒服多了{:10_297:}
Button 简易按钮
是不是觉得太简单,甚至有点简陋{:10_307:} ,既然如此那就上难度
Button (master=None,pos=, draw=, text=None, pad=, size=, command=None, variable=None,alpha=255)
master : 该对象绘制的对象(跟随移动,而不是真的绘制在上面),如果None就是绘制在screen上 -> Frame
pos : 该对象左上角的坐标位 ->
draw :
第一种使用方法:按钮填充该颜色 ->
第二种使用方法:按钮的绘制函数 draw(image) -> def draw(image):
image.fill((255,0,0))
pygame.draw.rect(image,......
pygame.draw.circle(image,......
注意!draw函数中禁止给image赋值
size : 大小,如果设定了text值,则该属性无效 ->
text : 绘制在draw函数绘制的图像上的文字 -> Text对象
pad : 当设定text值时有效,将按钮的大小(size)设定为Text对象的(width+pad,height+pad) ->
command : 当该对象被点击时调用的函数 -> callback(函数名)
variable : 当该对象被点击时,command中函数的返回值 -> Variable
alpha : 透明度 ->int (0到255之间)
set_choose_image (self,draw,size=,text=None,pad=):
改变鼠标放在按钮上的样式
属性同上
注意!重新设置的图像初始image是一张透明的image,
不是鼠标普通状态下的图片,所以如有需要,请不要忘记设置size,text等。。。
set_down_image (self,draw,size=,text=None,pad=)
改变鼠标点击按钮时的样式
属性同上,注意事项同上
举个例子{:10_271:}
老规矩,从最简单的开始,生成一个默认的按钮:
# 生成控件
b1 = pgui.Button(
pos=,
)
guis.add(b1)
然后就可以看到
生成了一个默认按钮,
把鼠标移上去,按钮高亮了
点击鼠标左键,按钮变暗了
以上就是按钮的三种状态,材质全都可以自定义更改
我们小小自定义一下Button的普通材质:
# 生成控件
text=pgui.Label(
text="I'm Button",
color=(100,255,200),
font=(None,20)
)
b1 = pgui.Button(
pos=,
text=text,
pad=,
draw=(200,50,200),
)
guis.add(b1)
首先创建一个Label ,然后传给Button,效果如下:
然后我们试一下通过draw的第二种使用方法来修改选择状态的材质和按下状态的材质:
把代码加在后头
# 设置选中颜色
def draw(image):
image.fill((255,255,255))
rect=image.get_rect()
pygame.draw.rect(image,color=(0,0,0),rect=rect,width=2)
text=pgui.Label(
text="I'm Button",
color=(0,0,0),
font=(None,20)
)
b1.set_choose_image(draw=draw,text=text,pad=)
# 设置按下颜色
def draw(image):
image.fill((0,0,0))
text=pgui.Label(
text="I'm Button",
color=(255,255,255),
font=(None,20)
)
b1.set_down_image(draw=draw,text=text,pad=)
来看看效果吧~
怎么样是不是简简单单!{:10_298:}
接下来我们来试试让按下的按钮变大,并且给他一个command参数
首先,再生成一个按钮:
text=pgui.Label(
text="Click me",
font=(None,20)
)
def callback():
print("hello world!")
b2 = pgui.Button(
text=text,
pad=,
command=callback,
)
guis.add(b2)
可以看到,已经打印了"hello world!"
然后我们通过 set_pos方法 (该方法见UI类)
来设置一下这个按钮的位置: 在按钮1的右边,高度与按钮1相同
b2.set_pos("left",b1.rect.right+10)
b2.set_pos("top",b1.rect.top)
效果不错,是我想象中的样子{:10_298:}
然后我们来设置一下按下状态的材质:
text = pgui.Label(text="Click me",font=(None,25))
b2.set_down_image(text=text,pad=,draw=(180,180,180))
嘿嘿,成功啦!{:10_298:} {:10_298:} {:10_298:}
真是太方便啦!
抛砖引玉
这是一个很简单的Button与Label联动的例子,先看代码
注意:callback函数,variable对象,label中的值
首先,我们先做一个按钮:
# 生成控件
var1 = pgui.Variable("0")
t = pgui.Label(text="1",font=(None,20))
def callback():
return "1"
b1 = pgui.Button(
pos = ,
text=t,
draw=(100,255,255),
pad=,
command=callback,
variable=var1
)
guis.add(b1)
把第二个按钮放在第一个按钮的边上:
var2 = pgui.Variable("0")
t = pgui.Label(text="2",font=(None,20))
def callback():
return "2"
b2 = pgui.Button(
text=t,
draw=(100,255,255),
pad=,
command=callback,
variable=var2
)
b2.set_pos("left",b1.rect.right+10)
b2.set_pos("top",b1.rect.top)
guis.add(b2)
再做两个label,把他们摆好:
l1 = pgui.Label(text="0",font=(None,20),background=(255,255,100))
guis.add(l1)
l1.set_pos("top",b1.rect.bottom+10)
l1.set_pos("right",b1.rect.right)
l2 = pgui.Label(text="0",font=(None,20),background=(255,100,255))
guis.add(l2)
l2.set_pos("top",l1.rect.bottom+10)
l2.set_pos("right",b1.rect.right)
再放上最后一个按钮,摆好:
t = pgui.Label(text="OK",font=(None,20))
def callback():
l1.set_text(var1.get()+var2.get())
l2.set_text(str(int(var1.get())+int(var2.get())))
b3 = pgui.Button(
pos = ,
text=t,
draw=(100,255,255),
pad=,
command=callback,
)
b3.set_pos("left",b2.rect.right+10)
b3.set_pos("top",b1.rect.top)
guis.add(b3)
最后的结果是两行组件:
一行Button
一行Label
如下图:
依次点击上面的按钮,发现label中的文本发生了变化:
我们根据代码中的逻辑可以看出:
l1中的文本为var1和var2的拼接
l2中的文本为var1和var2的和
小试牛刀
我们目前已经解锁了两个组件:Label 、Button{:10_297:}
我们可以通过他们配合variable轻松的写一个计算器,来尝试一下吧~{:10_257:}
要把练习结果发在评论区哦~{:10_334:}
哪怕只作出来了一半也要发出来哦!{:10_295:}
答案会在教程末尾公布!
按钮中加入图片
先把素材拿好
看代码吧~
# 生成控件
def draw(image):
image.blit(pygame.image.load("火柴人.png"),)
b1 = pgui.Button(
pos=,
draw=draw,
size=,
)
guis.add(b1)
效果:
神奇的Effect
Effect
pygame-GUI专用的默认特效,提供了一些预设的效果给Button和Frame使用,
让你的作品轻松的变得美观,虽然现在只有4个效果,但以后一定会有更多让你惊艳的效果
使用方法:
输入image,会返回带有效果的image对象
把输出的image对象,贴在原本的image上
light (image=None,color=(255,255,255),width=0,alpha=(50))
生成高亮效果
width : 同pygame中draw的使用方法,决定了是完全填充还是只画边框
其他的同上
dark (image=None,color=(0,0,0),width=0,alpha=(50))
生成黑暗效果
属性: 同上
raised (image=None,light_color=(255,255,255),dark_color = (0,0,0),alpha=255,width=3)
生成突起效果
light_color : 明亮的颜色 -> (RGB)
dark_color : 阴影的颜色 -> (RGB)
width : 突起多少个像素 -> int 普通大小的按钮不建议超过10个像素,一般2-5个像素就足够了
其他属性 : 同上
sunken (light_color=(255,255,255),dark_color = (0,0,0),alpha=255,width=3)
生成凹陷效果
属性 :同上
举个例子{:10_271:}
这里给大家一个使用Effect中突起和凹陷效果的例子:
案例使用的是前面button的栗子
# 立体按钮
text = text=pgui.Label(
text="I'm 3D Button",
font=(None,20)
)
def draw(image):
image.fill((175,175,175))
image.blit(pgui.Effect.raised(image),)
b3 = pgui.Button(
text=text,
pad=,
draw=draw,
)
guis.add(b3)
b3.set_pos("left",b2.rect.right+10)
b3.set_pos("top",b2.rect.top)
可以看到按钮的普通效果已经变为了”凸起“
然后设置一下它的其他两个效果:
def draw(image):
image.fill((175,175,175))
image.blit(pgui.Effect.raised(image),)
image.blit(pgui.Effect.light(image),)
b3.set_choose_image(draw,text=text,pad=)
def draw(image):
image.fill((175,175,175))
image.blit(pgui.Effect.sunken(image),)
b3.set_down_image(draw,text=text,pad=)
看看效果~
真不错欸{:10_298:}
Frame 框架结构
注意!此UI类目前处于测试阶段,很多东西以后的版本可能会有比较大的变动
Frame (master=None, pos=,size=,draw=(190,190,190), title=False)
生成一个sprite对象 -> 类似与tkinter的frame,但是有更多使用方法,
例如当成窗口,成为某个组件的一部分
master : 该对象绘制的对象(跟随移动,而不是真的绘制在上面),如果None就是绘制在screen上 -> Frame
pos : 左上角位置
size : 大小
draw :
1、在这个部件中填充该颜色 -> / (R,G,B)
2、输入一个的绘制函数 draw(image) -> def draw(image):
image.fill((255,0,0))
pygame.draw.rect(image,......
pygame.draw.circle(image,......
title : 是否有标题 -> bool
set_close_button (pos=,draw=_default_close_button_draw,text=None,pad=,size=,alpha=255)
设置close_button的函数 返回Button组件
draw :None时会生成一个红色的大叉
其他属性 : 与Buton组件相同
set_title (text=Label(text="pygame-GUI",font=(None,15),color=(0,0,0)),pad = ,draw=(255,255,255))
设置title的函数
如果title为True会自动生成默认的标题
draw : 在标题栏区域内绘制,其他同上
其他属性同上
举个例子{:10_271:}
还是老规矩,从最简单的开始~
# 生成控件
f1 = pgui.Frame(pos=,draw=(0,0,0),size=)
guis.add(f1)
可以看到,出现了一个黑色的方块
然后做一个variable变量:num:
num = pgui.Variable(0)
我们往里面塞一些按钮和文本对象:
按钮1:
def draw(image):
image.fill((200,200,200))
pygame.draw.polygon(image,color=(0,0,0),points=[,,])
def callback():
if num.get() < 100:
num.set(num.get()+5)
l1.set_text(str(num.get()))
b1 = pgui.Button(master=f1,size=,draw=draw,command=callback)
b1.set_pos("right",f1.rect)
guis.add(b1)
按钮2:
def draw(image):
image.fill((200,200,200))
pygame.draw.polygon(image,color=(0,0,0),points=[,,])
def callback():
if num.get() > 0:
num.set(num.get()-5)
l1.set_text(str(num.get()))
b2 = pgui.Button(master=f1,size=,draw=draw,command=callback)
b2.set_pos("right",f1.rect)
b2.set_pos("bottom",f1.rect)
guis.add(b2)
然后放上去一个Label:
l1 = pgui.Label(master=f1,text=str(num.get()),font=(None,40),color=(255,255,255))
guis.add(l1)
然后我们看看效果:
非常好!!一个建议的数值输入器就完成啦!{:10_298:} {:10_298:} {:10_298:}
通过num.get()就可以得到输入的数哦!{:10_279:}
我们来尝试一下改变他的位置:
f1.set_pos("right",width)
可以看到,整个数值编译器一块儿挪到最右边啦~
是不是超级方便!!!{:10_254:}
至此,我们完成了一个自定义的组件!是不是很有成就感!{:10_298:}
=============================================================
小美化
然后我们稍稍美化一下,用Effect!
先看效果:
先动动脑子,再想代码哦!
# 生成控件
f1 = pgui.Frame(pos=,draw=(85,85,85),size=)
guis.add(f1)
num = pgui.Variable(0)
def draw(image):
image.fill((200,200,200))
pygame.draw.polygon(image,color=(0,0,0),points=[,,])
image.blit(pgui.Effect.raised(image),)
def callback():
if num.get() < 100:
num.set(num.get()+5)
l1.set_text(str(num.get()))
b1 = pgui.Button(master=f1,size=,draw=draw,command=callback)
b1.set_pos("right",f1.rect)
def draw(image):
image.fill((200,200,200))
pygame.draw.polygon(image,color=(0,0,0),points=[,,])
image.blit(pgui.Effect.sunken(image),)
b1.set_down_image(draw=draw,size=)
guis.add(b1)
def draw(image):
image.fill((200,200,200))
pygame.draw.polygon(image,color=(0,0,0),points=[,,])
image.blit(pgui.Effect.raised(image),)
def callback():
if num.get() > -0:
num.set(num.get()-5)
l1.set_text(str(num.get()))
b2 = pgui.Button(master=f1,size=,draw=draw,command=callback)
b2.set_pos("right",f1.rect)
b2.set_pos("bottom",f1.rect)
def draw(image):
image.fill((200,200,200))
pygame.draw.polygon(image,color=(0,0,0),points=[,,])
image.blit(pgui.Effect.sunken(image),)
b2.set_down_image(draw,size=)
guis.add(b2)
def draw(image):
image.fill((100,100,100))
image.blit(pgui.Effect.sunken(image,width=5),)
f2 = pgui.Frame(master=f1,size=(f1.rect-15,f1.rect),draw=draw)
guis.add(f2)
l1 = pgui.Label(pos=(6,3),master=f2,text=str(num.get()),font=(None,40),color=(255,255,255))
guis.add(l1)
弹窗例子{:10_271:}
注意!此操作目前处于测试阶段,很多东西以后的版本可能会有比较大的变动
老规矩,我们从最简单的开始{:10_315:}
# 生成控件
f1 = pgui.Frame(pos=,draw=(85,85,85),size=,title=True)
guis.add(f1)
然后我们设置一下标题:
title = pgui.Label(text="pygameGUI-Frame-Window",font=(None,20))
f1.set_title(text=title,pad=)
拖动一下试试:
然后我们给他加一个关闭按钮:
b = f1.set_close_button()
b.set_pos("right",f1.rect)
guis.add(b)
不错!我们往里面塞点东西试试:
Label:
l = pgui.Label(master=f1,pos=(10,35),text="I am Frame!",font=(None,20),color=(255,255,255))
guis.add(l)
Button:
l = pgui.Label(master=f1,pos=(10,35),text="click me!",font=(None,20),color=(255,255,255))
b = pgui.Button(master=f1,pos=(10,60),text=l,pad=)
guis.add(b)
可以看到,再拖动的时候,其他组件跟着一起动了,关闭的时候,其他组件一起消失了{:10_315:}
是不是很有趣{:10_328:}
小试牛刀答案:计算器
好啦,万众瞩目的计算器参考答案来啦!
参考答案
未来的设想
Frame组件不再负责窗口的创建,而是由新的组件代替,这个组件可以由暂停其他组件的效果
Button里command的函数可以支持传参
新增一些更强大的按钮组件,如:支持双击,长按。。。
新增一个滑块组件,可以与Frame搭配,制作成滑条
正在更新。。。
更新中。。。。
您都看到这了给个评分在走呗{:10_257:}
支持,另外求开源 歌者文明清理员 发表于 2023-8-15 14:10
支持,另外求开源
有空会开源的 cjjJasonchen 发表于 2023-8-15 14:12
有空会开源的
https://www.zhihu.com/question/33573424 歌者文明清理员 发表于 2023-8-15 14:13
https://www.zhihu.com/question/33573424
{:10_282:}
我一不会魔法上网(fanqiang),二没学过git
别着急
多少给我一点时间吧 cjjJasonchen 发表于 2023-8-15 14:16
我一不会魔法上网(fanqiang),二没学过git
别着急
要是 Github 要魔法,你当我 v*n 限额还没到? 激动人心,无法言表,真是难得一遇的好帖! Ewan-Ahiouy 发表于 2023-8-15 15:02
激动人心,无法言表,真是难得一遇的好帖!
{:10_257:} Ewan-Ahiouy 发表于 2023-8-15 15:02
激动人心,无法言表,真是难得一遇的好帖!
评个分喵{:10_254:} cjjJasonchen 发表于 2023-8-15 15:06
评个分喵
没有额度了{:10_266:}明天叫我评! Ewan-Ahiouy 发表于 2023-8-15 15:07
没有额度了明天叫我评!
谢谢{:10_257:} {:10_275:} {:10_328:} {:5_106:} {:5_106:} 评分了 小小麦乐鸡 发表于 2023-8-15 16:21
{:10_257:} 琅琊王朝 发表于 2023-8-15 16:32
评分了
感谢支持{:10_257:} 8/15已更新! {:7_146:}