IMGUI快速入門

赵青青發表於2024-07-21

資源大全

官方資源

  1. 原始碼+例子:ocornut/imgui: Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies (github.com)
  2. python繫結:pyimgui/pyimgui: Cython-based Python bindings for dear imgui (github.com)
  3. 除錯IMGUI自身:除錯工具 ·ocornut/imgui 維基 (github.com)
  4. 線上示例,可定位到程式碼:ImGui Manual (pthom.github.io)
  5. Getting Started · ocornut/imgui Wiki (github.com)

其它

每個控制元件都帶圖示例:ImGui 簡單使用 - 無形深空 - 部落格園 (cnblogs.com)

快速入門

使用vs開啟下載的dear imgui,demo中13個project,他們之間沒有差異,只是dx或opengl等版本不一樣,示例程式碼在imgui_demo.cpp ShowDemoWindow

右鍵選單(popups)

if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
{
    selected = n;
    ImGui::Text("This a popup for \"%s\"!", names[n]);
    if (ImGui::Button("Close"))
        ImGui::CloseCurrentPopup();
    ImGui::EndPopup();
}
ImGui::SetItemTooltip("Right-click to open popup");

image-20240602161724930

閱讀習慣:控制元件Label右置,如何左置?

image-20240602210226755

pyimgui.begin("test window")

# default label
pyimgui.input_int("default label", 0)

# left label
pyimgui.text("left label")
pyimgui.same_line()
pyimgui.input_int("##left label item", 0)

pyimgui.end()

中文處理

中文亂碼

中文亂碼:TO_UTF8_CSTR("顯示或隱藏掛點及掛件"));

輸入框無法輸入中文

字型要支援中文,否則只能用英文輸入法,對原始碼修改

imgui.InputText

TreeNodeEx vs TreeNode

有兩種樹控制元件,建議使用新版的TreeNodeEx ,下面解釋下這兩種樹控制元件的區別

TreeNode

TreeNode是一個較舊的函式,它顯示一個簡單的樹,沒有互動性,如下所示,

img

TreeNodeEx

TreeNodeEx是一個較新的函式,它透過列舉支援大量選項,ImGuiTreeNodeFlags可用來設定當前選中狀態

img

ImGuiTreeNodeFlags flag = ImGuiTreeNodeFlags_DefaultOpen;//樹預設是開啟的
if (HAS_CHILDREN)
{
    flags |= ImGuiTreeNodeFlags_Leaf;//沒有子節點的就不顯示箭頭
}
flags |= ImGuiTreeNodeFlags_OpenOnArrow;//選擇非葉節點不會切換選中狀態
if (IS_SELECTED)
{
    flags |= ImGuiTreeNodeFlags_Selected; //高亮選中當前節點
}
if (ImGui::TreeNodeEx("root", flag)) //這裡返回的bool是樹節點是否處於開啟狀態,而不是點選狀態
{
    // Call ImGui::TreeNodeEx() recursively to populate each level of children
  	if (ImGui::IsItemClicked())
    {
        // 當節點被點選時觸發事件
    }
    ImGui::TreePop();  // 在結尾處必須要的
}  

資料:ImGui 樹節點 •TreeNode與TreeNodeEx

佈局Layout

有以下方法用來佈局

  1. SameLine
  2. SetCursorX
  3. table或列

SameLine

// Aligned to arbitrary position. Easy/cheap column.
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)");
ImGui::Text("Aligned");
ImGui::SameLine(150); ImGui::Text("x=150");
ImGui::SameLine(300); ImGui::Text("x=300");
ImGui::Text("Aligned");
ImGui::SameLine(150); ImGui::SmallButton("x=150");
ImGui::SameLine(300); ImGui::SmallButton("x=300");

image-20240603112503343

固定座標,視窗拉大座標也不改變

table

請使用新的table api,文件:新表 API (1.80 #3740 ·Ocornut/Imgui (github.com),支援功能如下:

  • 邊框和奇數行/偶數行背景顏色選項,滑鼠滑過的高亮
  • 隱藏特定的列,可以調整列的大小
  • 排序,每個表頭都可以排序

可以看table / Advanced這個例子

image-20240603142730964

按鈕無法點選(ID衝突)

https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-why-is-my-widget-not-reacting-when-i-click-on-it

ImGui隱式維護ID,控制元件樹中的控制元件路徑被hash來標識一個控制元件

每個控制元件的介面一般都有label,是該控制元件的ID,ID可以是字串(label引數),索引,或者指標

所以傳空串就會導致無法互動,解決辦法是用##XXX來標識,##後的內容在顯示時被忽略

因為複雜的控制元件其實維護了狀態,比如樹節點,有開關狀態,所以在幀之間需要標識,這個控制元件呼叫就是這個控制元件

錯誤示例

pyimgui.begin("test window")

# ID conflict
if pyimgui.button("button"): # ID = hash of ("test window", "button")
	IINFO("button1")

if pyimgui.button("button"): # ID = hash of ("test window", "button")
	IINFO("button2")

pyimgui.end()

這個示例中,兩個button的Label(ID)都叫button,因為這個Label也是ID,相同ID衝突可能導致其中一個button無法響應點選事件或同時響應事件。

解決辦法

Label中新增"##",##後的內容不會顯示在皮膚上,可以在Label後新增"##ID"內容來做ID區分,如:

if pyimgui.button("button##foo1"):  # ID = hash of ("test window", "button##foo1")
	IINFO("button1")

if pyimgui.button("button##foo2"):  # ID = hash of ("test window", "button##foo2")
	IINFO("button2")

##和###

Label中,"##ID"後的內容不會顯示在皮膚上

您可能需要使用“###”運算子構建一個字串,以保留帶有變數標籤的常量 ID)

static char name[32] = "Label1";
char buf[64];
sprintf(buf, "Button: %s###Button", name); / ### operator override ID ignoring the preceding label
ImGui::Button(buf); //顯示的是Button:Label1

雙擊事件

但是碰到個問題,在TreeNodeEx的子節點中新增雙擊後,無法預設選中這個節點

is_selected = False
def test():
    opened = imgui.TreeNodeEx(name, flags=flags)
    if imgui.Selectable(name,is_selected,imgui.ImGuiSelectableFlags_AllowDoubleClick):
        if imgui.IsMouseDoubleClicked() and getattr(entity, 'model', None): #雙擊顯示與隱藏
            entity.model.visible = not entity.model.visible

FAQ

itempick的作用還需要再看看