如何在ImGui::ListBox中使用存储自定义对象的vector?
问题原因
你遇到编译错误的核心原因是Dear ImGui 原生未提供直接接收std::vector<自定义类型>作为入参的ImGui::ListBox重载版本。原生ListBox仅支持两类传入方式:一类是直接传入C风格字符串数组,另一类是传入自定义渲染回调、数据指针来适配任意自定义类型的展示需求。
实现方法
方法1:使用回调适配版ListBox(实现简单,适合纯文本展示项)
这个方案用ImGui预留的自定义Getter回调,把vector中的自定义对象格式化成展示文本,不需要额外写渲染逻辑,代码量最小。
- 首先匹配ImGui要求的回调签名,回调内部根据索引从vector中取出对应
Waypoint对象,把所有属性格式化成字符串即可。 - 调用ListBox时把vector指针作为用户数据传入,同时传入vector当前长度作为总项数,天然支持每帧动态更新内容。
完整示例代码:
// 自定义Waypoint类沿用你的定义 class Waypoint { public: int x, y, z; char action; }; // 每帧渲染逻辑中 std::vector<Waypoint> listbox_items; // 测试填充数据 Waypoint wp1; wp1.action = 'R'; wp1.x = 100; wp1.y = 100; wp1.z = 7; listbox_items.push_back(wp1); Waypoint wp2; wp2.action = 'S'; wp2.x = 100; wp2.y = 100; wp2.z = 6; listbox_items.push_back(wp2); static int listbox_item_current = 0; // 选中索引从0开始,初始值1代表默认选中第二项 ImGui::ListBox( "listbox::Cavebot", &listbox_item_current, // 无捕获lambda可直接转为ImGui要求的函数指针,无需单独定义全局函数 [](void* user_data, int idx, const char** out_text) -> bool { const auto* waypoint_vec = static_cast<const std::vector<Waypoint>*>(user_data); // 索引越界直接返回false if (idx < 0 || idx >= waypoint_vec->size()) return false; const Waypoint& wp = (*waypoint_vec)[idx]; // 静态缓冲区存储格式化后的展示文本,确保指针在回调返回后仍有效 static char display_buf[128]; snprintf(display_buf, sizeof(display_buf), "Waypoint %d | Action: %c | Position: (%d, %d, %d)", idx, wp.action, wp.x, wp.y, wp.z); *out_text = display_buf; return true; }, (void*)&listbox_items, // 把vector指针作为用户数据传入回调 listbox_items.size() // 传入当前vector的总长度 ); // 后续可直接通过listbox_item_current获取选中的航点对象 if (listbox_item_current >= 0 && listbox_item_current < listbox_items.size()) { Waypoint& selected = listbox_items[listbox_item_current]; // 编写选中后的业务逻辑即可 }
方法2:手动控制列表项渲染(灵活度高,支持自定义样式)
如果你需要给列表项加彩色文本、图标、按钮等复杂元素,直接用BeginListBox/EndListBox接口自行循环渲染每一项,可控性更强:
if (ImGui::BeginListBox("listbox::Cavebot")) { for (int i = 0; i < listbox_items.size(); i++) { const bool is_selected = (listbox_item_current == i); const Waypoint& wp = listbox_items[i]; // 自定义渲染逻辑:比如动作类型用橙色高亮 ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), "[%c]", wp.action); ImGui::SameLine(); ImGui::Text("Pos: (%d, %d, %d)", wp.x, wp.y, wp.z); // 处理点击选中 if (ImGui::IsItemClicked()) listbox_item_current = i; // 给选中项加默认高亮 if (is_selected) ImGui::SetItemDefaultFocus(); } ImGui::EndListBox(); }
注意事项
- 两种方案都天然支持动态更新:每帧渲染时会自动读取vector的最新长度和内容,增删元素、修改属性后下一帧会自动展示最新结果,不需要额外调用刷新接口。
- 动态增删vector元素后,注意检查
listbox_item_current是否越界,如果越界要手动重置为合法值(比如设为0,或者最后一项的索引),避免出现选中空项的问题。 - 回调中不要使用栈上临时字符数组存储展示文本,否则会出现内存访问错误,必须用静态缓冲区或者全局缓冲区保证指针有效性。
内容的提问来源于stack exchange,提问作者kuhi
相关产品推荐
相关产品推荐

