【Godot4.2】菜单栏生成函数库menuDB

概述

关于Godot的手动菜单栏制作,我已经在之前的文章中有所描述。

但是对于一些场景,手动制作菜单仍然是一个比较低效的做法。所以我将MenuBar以及基于HBoxContainer+MenuButton创建菜单栏写成了一个静态函数库。

利用此函数库我们可以用函数形式构造PopupMenuMenuButtonMenuBar以及基于HBoxContainer+MenuButton创建的菜单栏。

另外我自定义3种资源,来定义和存储单个菜单栏、单个菜单和单个菜单项所需的数据:

  • MenuBarData:存储定义单个MenuBar所需的数据
  • MenuData:存储定义单个菜单所需的数据
  • PopupMenuItem:存储单个菜单项所需的数据

当然我的本意是基于这个函数库构建更简单的菜单栏自定义控件。

函数库代码

# ========================================
# 名称:menuDB
# 类型:静态函数库
# 描述:专用于【生成菜单栏】的静态函数库
# 作者:巽星石
# Godot版本:v4.2.1.stable.official [b09f793f5]
# 创建时间:202422718:45:28
# 最后修改时间:202422721:51:11
# ========================================
class_name menuDB

# -------------- 构造MenuBar或基于HBoxContainer+MenuButton的水平菜单栏 --------------
# 构造并返回有完整结构的MenuBar
static func menu_bar(menu_bar_data:MenuBarData) -> MenuBar:
	var bar = MenuBar.new()
	# 遍历MenuBar数据,创建PopUp
	for menu_data in menu_bar_data.menus:
		var menu = popup_menu(menu_data.text,menu_data.items,menu_bar_data.icon_max_width)
		bar.add_child(menu)
	return bar

# 构造并返回多个MenuButton水平排列的HBoxContainer
static func hbox_menu_bar(menu_bar_data:MenuBarData) -> HBoxContainer:
	var bar = HBoxContainer.new()
	# 遍历MenuBar数据,创建PopUp
	for menu_data in menu_bar_data.menus:
		var menu = menu_button(menu_data.text,menu_data.icon,menu_data.items,menu_bar_data.icon_max_width)
		bar.add_child(menu)
	return bar


# -------------- 构造 PopupMenuMenuButton --------------
# 构造并返回一个带有菜单项的PopupMenu
static func popup_menu(
					text:String = "MenuButton",  # 按钮文本
					items:Array[PopupMenuItem] = [], # 菜单项数据集
					items_icon_max_width = 16        # 菜单项图标的最大宽度
				) -> PopupMenu:
	# --------------- 创建MenuButton ---------------
	var menu = PopupMenu.new()
	menu.name = text
	# --------------- 遍历items,为PopupMenu添加菜单项 ---------------
	for item in items:
		popup_menu_add_item(menu,item,items_icon_max_width)
	return menu


# 构造并返回带有菜单项的MenuButton
static func menu_button(
					text:String = "MenuButton",  # 按钮文本
					icon:Texture2D = null,           # 按钮图标
					items:Array[PopupMenuItem] = [], # 菜单项数据集
					items_icon_max_width = 16        # 菜单项图标的最大宽度
				) -> MenuButton:
	# --------------- 创建MenuButton ---------------
	var btn = MenuButton.new()
	btn.text = text
	btn.icon = icon
	# --------------- 获取其PopupMenu ---------------
	var menu:PopupMenu = btn.get_popup()
	# --------------- 遍历items,为PopupMenu添加菜单项 ---------------
	for item in items:
		popup_menu_add_item(menu,item,items_icon_max_width)
	return btn


# -------------- PopupMenu菜单项添加 --------------
# 通过PopupMenuItem资源数据为PopupMenu添加一个菜单项
static func popup_menu_add_item(menu:PopupMenu,item:PopupMenuItem,icon_max_width = 16) -> void:
	var index = menu.item_count # 当前项索引 = 已有菜单项总数
	# 创建纯文本菜单项
	menu.add_item(item.text)
	# 设置附加选项
	if item.icon:              # 图标
		menu.set_item_icon(index,item.icon)
	menu.set_item_icon_max_width(index,icon_max_width)        # 图标最大宽度
	if item.checkable:         # 复选框 形式
		menu.set_item_as_checkable(index,item.checkable)
	if item.radio_checkable:   # 单选框 形式
		menu.set_item_as_radio_checkable(index,item.radio_checkable)
	if item.separator:         # 带分割线 形式
		menu.set_item_as_separator(index,item.separator)
	if item.shortcut:          # 快捷键 + 是否全局
		menu.set_item_shortcut(index,item.shortcut,item.shortcut_global)
	menu.set_item_shortcut_disabled(index,item.shortcut_disabled)   # 快捷键是否禁用
	
	menu.set_item_checked(index,item.checked)    # 是否选中(仅在单选框或复选框形式下)
	menu.set_item_disabled(index,item.disabled)  # 是否禁用
	menu.set_item_tooltip(index,item.tooltip)    # 鼠标提示文本
	
	if item.sub_menu.size() > 0:        # 如果菜单项存在子菜单项
		var sub_popup = PopupMenu.new() # 创建子菜单
		sub_popup.name = "%d_%s_sub_popup" % [index,item.text]  # 创建唯一名称
		# 添加子菜单项
		for sub_item in item.sub_menu:
			popup_menu_add_item(sub_popup,sub_item,icon_max_width)
		# 添加为当前PopupMenu的子节点
		menu.add_child(sub_popup)
		menu.set_item_submenu(index,sub_popup.name)  # 为当前项指定子菜单的名称

3种自定义数据结构

MenuBar

@tool
# 单个MenuBar数据
class_name MenuBarData extends Resource
	
@export var menus:Array[MenuData]           # 菜单列表
@export var icon_max_width = 16       # 菜单项图标的最大宽度

MenuData

@tool
# 单个菜单数据
class_name MenuData extends Resource

@export var text:String                     # 按钮文本
@export var icon:Texture2D                  # 按钮图标
@export var items:Array[PopupMenuItem]      # 菜单项

PopupMenuItem

@tool
# PopupMenu单个菜单项数据
class_name PopupMenuItem extends Resource

# 基础设置
@export var text:String             # 文本
@export var icon:Texture2D          # 图标
# 特殊形式
@export var checkable:bool          # 复选框 形式
@export var radio_checkable:bool    # 单选框 形式
@export var separator:bool          # 带分割线 形式
# 快捷键
@export var shortcut:Shortcut       # 快捷键
@export var shortcut_global:bool    # 快捷键是否全局
@export var shortcut_disabled:bool  # 快捷键是否禁用
# 选中与禁用
@export var checked:bool            # 选中
@export var disabled:bool           # 禁用
# 鼠标提示文本
@export var tooltip:String          # 鼠标提示文本
# 子菜单
@export var sub_menu:Array[PopupMenuItem]     # 子菜单

基于函数库创建自定义MenuBar节点

# ========================================
# 基于menuDB函数库的自定义MenuBar节点
# ========================================
@tool
class_name myMenuBar extends MenuBar

@export var data:MenuBarData:
	set(val):
		data = val
		create()
		
# 根据MenuBarData创建菜单和菜单项
func create() -> void:
	# 遍历MenuBar数据,创建PopUp
	for menu_data in data.menus:
		var menu = menuDB.popup_menu(menu_data.text,menu_data.items,data.icon_max_width)
		add_child(menu)

我们可以看到myMenuBar类型有一个Data参数,我们需要为其设定MenuBarData类型的资源。
在这里插入图片描述
运行后的效果如下:
在这里插入图片描述
可以看到这种自定义资源多层嵌套形式在Godot检视器面板上就是一种灾难。

所以更好的做法是基于字典的解析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巽星石

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值