GroupButtons
概述
读者朋友们好,我是巽星石,这是我的Godot4.2文件系统自定义控件系列文章。
在很多程序或插件设计中,都会用到一堆按钮的形式,好处是比较直观,用啥点啥,本质上相当于一个简化的二级树形导航结构。
这种结构我在自己编写的Godot插件myAdd中使用过,这次是基于Godot4.2重新编写,并通过解析自定义数据形式简化使用的版本。
代码
同样只需要拷贝下面的代码到你的插件或程序项目(Godot4.2或以上)中,可以命名为“GroupButtons.gd”。
# =============================================
# 名称:GroupButtons
# 类型:自定义节点(扩展控件)
# 描述:专用于显示分组按钮
# 作者:巽星石
# Godot版本:v4.2.1.stable.official [b09f793f5]
# 创建时间:2024年2月7日23:59:18
# 最后修改时间:2024年2月8日01:30:44
# =============================================
@tool
extends PanelContainer
class_name GroupButtons
## 按钮点击时触发
signal button_clicked(group_title:String,title:String)
## 包含分组和具体按钮文本的自定义数据,格式如下:[br]
## 分组标题==按钮名称||按钮名称...[br]
## 分组标题==按钮名称||按钮名称...[br]
## ...
@export_multiline var data:String = "":
set(val):
data = val
reload()
## 展开图标,显示在分组按钮右侧
@export var expand_icon:Texture2D:
set(val):
expand_icon = val
reload()
## 收起图标,显示在分组按钮右侧
@export var fold_icon:Texture2D:
set(val):
fold_icon = val
reload()
var root:VBoxContainer # 添加分组的VBox容器
# 实例化时进行初始化构建
func _init():
# 创建最基础的容器框架
var scroll = ScrollContainer.new()
var vbox = VBoxContainer.new()
vbox.size_flags_horizontal=Control.SIZE_EXPAND_FILL
scroll.add_child(vbox)
add_child(scroll)
root = vbox
# 根据data重新加载整个分组按钮列表
func reload():
# 清空原有分组
for child in root.get_children():
child.queue_free()
# 加载新分组
var datas = data.split("\n")
for dt in datas:
add_group(dt)
# 根据分组数据(形如“分组标题==按钮名称||按钮名称”)添加一个分组
func add_group(gup_data:String):
var gup_name = gup_data
var datas = gup_data.split("==")
if datas.size()>0:
gup_name = datas[0]
# 创建分组和分组标题按钮
var vbox = vbox(group_button(gup_name))
var grid = grid()
grid.columns = 2
# 创建具体的按钮
if datas.size()>1:
var btns = datas[1].split("||")
for bt in btns:
var btn = button(bt)
btn.size_flags_horizontal=Control.SIZE_EXPAND_FILL
## 按钮点击处理
btn.connect("pressed",func():
emit_signal("button_clicked",gup_name,bt)
)
grid.add_child(btn)
vbox.add_child(grid)
root.add_child(vbox)
# ============================ 控件生成函数 ============================
# ============== 说明:以下函数仅用于生成控件或容器,用于简化代码
# 创建并返回一个VBoxContainer实例,并添加child为子节点
func vbox(child:Control = null) -> VBoxContainer:
var v_box = VBoxContainer.new()
if child:
v_box.add_child(child)
return v_box
# 创建并返回一个GridContainer实例,并添加child为子节点
func grid(child:Control = null) -> GridContainer:
var g = GridContainer.new()
if child:
g.add_child(child)
return g
# 创建并返回一个按钮实例
func button(title:String) -> Button:
var btn = Button.new()
btn.text = title
return btn
# 创建并返回一个分组标题按钮实例
func group_button(gup_name:String) -> Button:
var gup_btn = button(gup_name)
gup_btn.icon = fold_icon
gup_btn.expand_icon = true
gup_btn.icon_alignment=HORIZONTAL_ALIGNMENT_RIGHT
gup_btn.flat = true
# 分组按钮点击处理
gup_btn.connect("pressed",func():
var parent = gup_btn.get_parent()
if parent is VBoxContainer:
var grid = parent.get_child(1)
if grid is GridContainer:
grid.visible = not grid.visible
if gup_btn.icon == fold_icon:
gup_btn.icon = expand_icon
else:
gup_btn.icon = fold_icon
)
return gup_btn
使用方法
脚本拷贝和创建到项目中后,在具体场景中添加节点。
将控件放大至合适大小,在检视器面板设定参数,其中data属性采用的是我自定义的一种数据形式,格式如下:
分组标题==按钮名称||按钮名称...
分组标题==按钮名称||按钮名称...
...
也就是说:
- 每一行描述一个分组
==
之前是分组标题,之后==
之后是分组下的按钮标题,每个按钮标题之间用||
作为分隔
expand_icon和fold_icon用于在分组折叠或展开时显示。
因为本质上GroupButtons是基于PanelContainer,因此你可以用自定义的StyleBox资源修饰它。
通过自定义背景颜色,就可以获得更好的样式:
以下是调整后的样式:
但是在制作编辑器插件时,我更倾向于不去调整原始的控件和容器样式,因为一切都可以直接跟随编辑器的样式发生变化。
获取按钮点击信息
通过连接和处理自定义信号button_clicked
,可以获取每个按钮的分组标题及其自身的标题,通过match
之类的分支结构,可以进行具体的处理。
信号处理代码如下:
func _on_group_button_button_clicked(group_title, title):
print(group_title,":",title)
pass