【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的定制可以使用哪些脚本来实现
- 确定定制UI的代码范围
- 为UI获取鼠标位置和UI渲染列表以及注册相关回调函数(IsItemHovered(),IsItemClicked()诸如此类)
- 利用ImVec2进行排版,利用ImU32进行颜色的显示
- 或许会用到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面板地实操还需要较多的脚本编写。