ImGui自定义组件以及相关回调函数(类事件)绑定

【ImGui入门教程】【中文配音】【24】在ImGui中自定义按钮设计 – 渐变和悬停效果_哔哩哔哩_bilibili

有一个B站的搬运,实现了一些效果,能够对ImGui的button进行一个自定义的效果。函数整体是这样的

bool CustomButton(const char* label){
	//PushID用于管理当前的UI资源,ImGui是通过ID来管理各UI的
	ImGui::PushID(label);
	
	ImVec2 button_size = ImVec2(120,30);
	ImVec2 p = ImGui::GetCursorScreenPos();
	//Button类函数都会返回一个区域是否被点击
	//使用InvisibleButton可以很好地不影响画面设置是否被点击
	bool is_clicked = ImGui::InvisibleButton(label,button_size);
	ImDrawList* draw_list = ImGui::GetWindowDrawList();

	ImU32 color_bg = ImGui::GetColorU32(ImVec4(0.2f,0.3f,0.3f,1.0f));
	ImU32 color_hover = ImGui::GetColorU32(ImVec4(0.6f,0.3f,0.9f,1.0f));
	ImU32 color_g1 = ImGui::GetColorU32(ImVec4(0.2f,0.3f,1.0f,1.0f));
	ImU32 color_g2 = ImGui::GetColorU32(ImVec4(1.0f,0.3f,0.3f,1.0f));
	ImU32 color_text = ImGui::GetColorU32(ImVec4(1.0f,1.0f,1.0f,1.0f));

	draw_list->AddRectFilledMultiColor(p,ImVec2(p.x+button_size.x,p.y+button_size.y),
		color_g1,color_g2,color_g2,color_g1);
	
	if(ImGui::IsItemHovered()){
		draw_list->AddRectFilled(p,ImVec2(p.x+button_size.x,p.y+button_size.y),color_hover);
	}

	ImVec2 text_size = ImGui::CalcTextSize(label);
	ImVec2 text_pos = ImVec2(p.x+(button_size.x-text_size.x)/2,p.y+(button_size.y-text_size.y)/2); 
	draw_list->AddText(text_pos,color_text,label);

	ImGui::PopID();
	return is_clicked;
}

而从这之中,我们可以了解到UI的定制可以使用哪些脚本来实现

  1. 确定定制UI的代码范围
  2. 为UI获取鼠标位置和UI渲染列表以及注册相关回调函数(IsItemHovered(),IsItemClicked()诸如此类)
  3. 利用ImVec2进行排版,利用ImU32进行颜色的显示
  4. 或许会用到Img相关选项进行进一步操作?有点像前端了!

进一步拓展的需求与功能

利用回调函数进行事件注册,确保对某label的回调触发,也可以作为游戏制作与页面制作的一种思路

#include <functional>

void RenderButton(const char* label, std::function<void()> callback) {
    if (ImGui::Button(label)) {
        callback(); // 按钮被点击时调用回调函数
    }
}

// 示例
void OnButtonClick() {
    std::cout << "Button clicked!" << std::endl;
}

void RenderUI() {
    RenderButton("Click Me", OnButtonClick);
}

不调用functional头文件的做法

这里callback可以传入一个int表示物体id然后执行是否渲染,或者说把他加入移除渲染队列

void func1(const char* label,void (*callback)(int),int id){
    if (ImGui::Button(label)){
        // 按钮被点击,调用回调函数
        callback(id);
    }
}

std::funtion和std::bind的使用

std::funtion和std::bind可以登场了。 std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda表达式、函数指针、以及其它函数对象等[1]。 std::bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的[2]。 关于他们的详细用法可以自行百度,如果有需要的以后出一期单独写,这里直接上代码,看std::funtion和std::bind如何在回调中使用。

原文链接:关于C++ 回调函数(callback) 精简且实用_c++ callback-CSDN博客

差异

使用std::function需要引入functional头文件,相比函数指针二者使用方法其实相同。至于其他差异,估计要看你使用代码的具体场景了

(53 封私信 / 71 条消息) C++ std::function 和函数指针相比有啥区别吗? - 知乎

分析

目前的渲染框架分析:

//准备场景物体的处理
prepare()

//渲染循环
while(){
	Render(scene,camera,light);//具体渲染操作
	RenderImGui();
}

我们ImGui是怎么做到变量的控制的呢?就是通过传入指针参数进行一个绑定。

于是我们就要考虑我们创建的变量的生命周期,类参数的可见性。

在该工程中,全局变量创建的只有GrassMaterial作为能够访问到的材质,所以我们能够绑定其参数。

以及我们创建的Scene指针,所以我们在main()函数中能够利用Scene来进行绘制

那么这种方式好吗?我们思考一下🤔

这意味着,如果我们多了一个物体,我们想要ImGui设置就要多一个全局变量。如果我们动态添加物体到渲染场景中,就非常不方便!!!

那么比较适合的方法是怎么做?

一种思想是新建一个类作为场景中左右物体的承载者,这个承载者可以是总的一个Scene。

也可以是一个所谓的渲染列表unordered_map<const char*,Obejct>存储所有注册的物体,然后如果我们要设置ImGui的参数,我们传入一个Object就能遍历其参数列表对参数以及Material进行一个设置

像诸如此类的方法,就能做到灵活地拓展面板元素,也相当于一个元素地排版吧

void ObjectImGuiSet(Object* obj){
	ImGui::PushID()
	
	ImGui::DragFloat3((float*)&obj->getPosition());//诸如此类
	
	ImGui::PopID()
}

然后我们需要思考的是,我们想要的一些排版是什么样的,然后根据上一篇博客对于组件的一些基本了解,可以对Object的一些值进行绑定,以让项目的UI面板有所谓物体的访问UI进行各项值的一个调整。目前先写到这,后面UI面板地实操还需要较多的脚本编写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值