Dear ImGui学习:组件ID
2024-03-17 17:33:41

问题

问题代码

1
2
3
4
5
6
7
if (ImGui::Button("Test1")) {
::OutputDebugStringA("Btn1 clicked");
}

if (ImGui::Button("Test1")) {
::OutputDebugStringA("Btn2 clicked");
}

点击第二个按钮是没有效果的,谷歌了一番后找到了原因,因为 Dear ImGui 有一个栈机制。
在内部 Dear ImGui 需要靠唯一的ID来追踪组件,而 Dear ImGui 默认将组件的Label参数当作是唯一ID,所以当有相同的Label时就产生了冲突。

在 Demo 中有个 Stack Tool 可以直观地查看栈情况。

解决方案

方法一:用##来标记唯一ID

1
2
3
4
5
6
7
if (ImGui::Button("Test1##id1")) {
::OutputDebugStringA("Btn1 clicked");
}

if (ImGui::Button("Test1##id2")) {
::OutputDebugStringA("Btn2 clicked");
}

##后面的字符串不会显示在组件上,这样就保证了栈里的ID是唯一的。

方法二:使用 PushID/PopID 方法

1
2
3
4
5
6
7
8
9
10
11
ImGui::PushID(0);
if (ImGui::Button("Test1")) {
::OutputDebugStringA("Btn1 clicked");
}
ImGui::PopID();

ImGui::PushID(1);
if (ImGui::Button("Test1")) {
::OutputDebugStringA("Btn2 clicked");
}
ImGui::PopID();

PushIDPopID成对使用,参数可以是数字,也可以是字符串,要保证唯一性。

知识点

  • 只有可交互式的组件才需要ID,比如ButtonInput等等。
  • 不同窗口之间的相同ID不会冲突。
  • 如果需要一个空Label就必须设置一个ID。
    1
    ImGui::Button("##id")
  • 使用###来禁止将Label部分纳入为ID。
    1
    2
    sprintf(buf, "My game (%f FPS)###MyGame", fps);
    Begin(buf);
    这样在栈里的实际ID是”MyGame”,而不是整个字符串。

参考

Buttons with identical labels do not work
About the ID Stack system