ImGui是一個為C++語言實現的、輕量、可信賴的、跨平台、功能豐富的用戶界面框架,它為程序開發者提供了簡單的工具使他們能為自己的程序添加圖形用戶界面。所有的控制項都是通過硬編碼的方式在一個OpenGL窗口渲染出來的,因此界面渲染效率非常高。同時,由於ImGui的實現非常簡單清晰,因而開發者容易根據自己的需求擴展定製化的控制項。ImGui只是一個跨平台的窗口、輸入、圖形繪製庫,它不提供音頻或者其他多媒體功能等其它與UI無關的功能。本篇文章中我們將對ImGui的繪製實踐進行探討。
一、基礎實現
ImGui的核心要素是客戶端和圖形依賴對於的庫,庫的實現可以包括OpenGL、Direct3D、Vulkan等。在初始化之後,程序需要不斷調用ImGui的渲染函數將界面渲染出來。我們可以通過以下代碼實現最基礎的ImGui界面:
#include "imgui.h" #include "imgui_impl_glfw.h" #include "imgui_impl_opengl3.h" // 初始化ImGui ImGui::Initialize(); ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init(glsl_version); // 每一幀渲染ImGui ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); ImGui::ShowDemoWindow(); // 示例窗口 ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
在上述代碼中,我們調用了ImGui的初始化函數並指定了使用OpenGL 3.0,同時實現了一個示例窗口。然後我們使用ImGui的渲染函數將繪製好的圖形界面展現在屏幕上。注意,這裡的ImGui實現依賴於glfw和OpenGL相關庫。
二、添加控制項實現
在實現了最基礎的ImGui界面之後,我們可以來嘗試一下添加一些常見的控制項。
1. Button控制項
我們可以通過ImGui::Button函數實現一個單行按鈕,並為其添加一個事件回調函數。下面的代碼顯示了如何實現一個簡單的Button控制項:
ImGui::Begin("Button"); if (ImGui::Button("Click me!")) std::cout << "Button clicked!" << std::endl; ImGui::End();
在上述代碼中,我們使用ImGui::Button函數並指定按鈕的名稱為”Click me!”。再在按鈕下方添加一個事件回調函數使得按鈕被點擊時會輸出一條信息到控制台上。除了回調函數外,ImGui::Button函數還支持傳遞參數控制按鈕的顯示面積、顏色、對準方式等。
2. 滾動條控制項
ImGui::Scrollbar函數可以實現一個可滾動的滾動條控制項,我們可以通過其提供的回調函數參數來實現滾動事件的監聽。下面的代碼演示了如何實現一個可滾動的滑塊滑動控制項:
static float scroll_value = 0.5f; // 初始值 ImGui::Begin("Scrollbar"); ImGui::Scrollbar("scrollbar", ImGuiAxis_X, &scroll_value, 0.0f, 1.0f); ImGui::End();
在上述代碼中,我們使用ImGui::Scrollbar函數來繪製一個滑動條,並為其指定了方向和範圍。通過&scroll_value可以獲取當前滑動條位置,將其傳遞給Animator的Update()函數就可以實現相關的控制代碼。
3. 標籤頁控制項
ImGui::TabBar函數實現了一個標籤頁控制項,我們可以通過其提供的回調函數參數實現標籤頁選擇後的效果。下面是一個實現簡單的標籤頁控制項:
static int tab_index = 0; ImGui::Begin("Tab bar"); if (ImGui::BeginTabBar("TabBar")) { if (ImGui::TabItem("Tab1")) tab_index = 0; if (ImGui::TabItem("Tab2")) tab_index = 1; ImGui::EndTabBar(); } ImGui::Text("Selected tab: %d", tab_index); ImGui::End();
在上述代碼中,我們使用ImGui::BeginTabBar和ImGui::TabItem函數分別為標籤頁控制項中的標籤欄和標籤頁添加標籤。當某一個標籤頁被選中時,回調函數tab_index會得到被選中的標籤頁的序號。再通過實現相關的切換代碼就可以實現標籤頁切換了。除此之外,我們還可以通過其他參數控制標籤頁的樣式、顏色、尺寸等。
三、繪製自定義控制項
ImGui的靈活性在於其可以輕鬆定製化各種控制項來滿足開發者的需求。本節將演示如何在ImGui中繪製一個自定義的動態圖形控制項。
1. 實現一個Animator類
動態圖形控制項需要一個Animator類來提供繪製相關的邏輯。下面的Animator類會在界面上繪製一個從一側到另一側移動的矩形:
class Animator { public: Animator() {} void Update(float delta_time) { float speed = 50.0f; m_position.x += speed * delta_time; if (m_position.x > 800.0f) { m_position.x = -50.0f; } } void Draw() { ImGui::GetWindowDrawList()->AddRectFilled(m_position, m_position + ImVec2(50.0f, 50.0f), IM_COL32(60, 60, 60, 255)); } private: ImVec2 m_position = ImVec2(-50.0f, 200.0f); };
在Animator中,我們實現了Update和Draw兩個函數。Update函數是通過delta_time計算動畫對象的位置,Draw函數則將動態圖形繪製到屏幕上。GetWindowDrawList()函數將返回ImGui提供的繪製列表控制器,我們可以在這個列表中添加我們需要繪製的所有的動態圖形。
2. 使用Animator類繪製動態圖形
我們可以在ImGui窗口的主循環中反覆更新和繪製Animator控制項:
Animator anim; while (!glfwWindowShouldClose(window)) { glfwPollEvents(); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); // 動畫控制項更新 float delta_time = 1.0f / ImGui::GetIO().Framerate; anim.Update(delta_time); // 繪製動畫控制項 anim.Draw(); // 將所有UI元素全部渲染 ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(window); }
在上述代碼中,我們在主循環中對Animator控制項的位置進行更新,並將其繪製到ImGui繪製列表中。其中delta_time物理值為當前幀的時間與前一幀的時間之差,通過待繪製動圖數據的時間與delta_time的區別來計算偏移量,從而實現運動效果。
四、結語
通過本文,我們已經可以初步了解ImGui繪製的實現流程,以及如何在其中添加、定製化各式各樣的控制項。當然,本文中只是演示了一些簡單的用例,對於深度定製化的控制項,我們還需通過ImGui本身提供的API函數,來實現各種更加豐富的功能表現。
原創文章,作者:QYOZ,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/145582.html