本教程将手把手带您用纯原生方式构建ImGui应用,无需CMake/第三方库。您将全程明了自己每个操作的意义,特别适合首次接触GUI开发的新手。
环境配置
安装VSCode
- 作用:轻量级代码编辑器,提供智能提示
- 操作 :
- 官网下载安装包 → 默认选项安装
- 安装后打开,按下
Ctrl+Shift+X
安装"C/C++ Extension Pack"
配置MinGW
- 作用:提供Windows下的GCC编译环境
- 操作 :
- 访问WinLibs下载MinGW-W64 GCC 14.2.0 + LLVM/Clang/LLD/LLDB 19.1.7的Release包
- 解压到
C:\mingw64
(路径不可含中文) - 右键开始菜单 → 系统 → 高级系统设置 → 环境变量 → 在Path中添加
C:\mingw64\bin
验证成功 :
打开CMD输入g++ -v
应显示类似gcc version 14.2.0
的版本信息
项目结构解析
创建标准目录
powershell
MyProject/
├─.vscode/ # VSCode专属配置
│ ├─tasks.json # 编译指令配置
│ └─settings.json # 头文件路径配置
├─libs/
│ └─imgui/ # ImGui核心库文件
└─src/
├─main.cpp # 窗口初始化代码(无需修改)
└─Application.hpp # 你的UI主战场
关键说明:
.vscode
:存放编辑器配置,避免每次手动设置libs/imgui
:集中管理第三方库,便于后续升级
获取ImGui源码
精准获取必要文件
- 访问Imgui的GitHub仓库
- 下载ZIP包后解压,按以下清单复制文件:
- 核心组件 (来自根目录):
imgui.cpp
,imgui.h
,imgui_*.cpp/h
imstb_*.h
系列文件
- Windows后端 (来自backends/):
imgui_impl_win32.h/cpp
imgui_impl_dx11.h/cpp
- 核心组件 (来自根目录):
为何需要后端文件 :
ImGui本身是平台无关的GUI库,需要特定平台的实现才能显示窗口。这里选择DirectX11作为渲染后端。
配置文件详解
tasks.json(编译指令)
json
{
"version": "2.0.0", // JSON 配置文件的版本号
"tasks": [ // 定义一个任务列表
{
"label": "Build main.exe", // 任务名称,方便识别
"type": "shell", // 任务类型,表示这是一个 shell 命令
"command": "g++", // 使用的编译器命令,这里是 g++
"args": [ // 传递给编译器的参数列表
"-I", // 指定头文件搜索路径
"${workspaceFolder}/libs/imgui", // imgui 库的头文件路径
"-I", // 再次指定头文件搜索路径
"${workspaceFolder}/include", // 项目自己的头文件路径
"src/main.cpp", // 要编译的主源文件
"${workspaceFolder}/libs/imgui/*.cpp", // imgui 库的所有实现文件
"-o", // 用于指定输出文件
"${workspaceFolder}/${workspaceFolderBasename}.exe", // 输出的可执行文件路径
"-static", // 静态链接,用于不依赖 DLL
"-L/mingw64/lib", // 指定库文件搜索路径
"-ld3d11", // 链接 Direct3D 11 库
"-ldxgi", // 链接 DXGI 库
"-luser32", // 链接 Windows 用户界面库
"-lgdi32", // 链接 GDI 图形设备接口库
"-lole32", // 链接 OLE 库
"-ldwmapi", // 链接 DWM API 库
"-ld3dcompiler", // 链接 D3D 编译器库
"'-Wl,-subsystem,windows'" // 容器选项:指定生成 Windows 应用程序
],
"group": { // 任务分组信息
"kind": "build", // 组的类型为构建
"isDefault": true // 设定为默认构建任务
}
}
]
}
settings.json(智能提示配置)
json
{
"C_Cpp.default.includePath": [ // C/C++ 扩展的默认头文件搜索路径
"${workspaceFolder}/include", // 项目中包含头文件的路径
"${workspaceFolder}/libs/imgui" // ImGui 库的头文件路径
],
"C_Cpp.default.Definition": [ // C/C++ 扩展的默认宏定义路径
"${workspaceFolder}/include" // 需要使用宏定义的头文件路径
],
"C_Cpp.errorSquiggles": "disabled", // 禁用错误波浪线提示
"C_Cpp.intelliSenseEngine": "default", // 使用默认的智能感知引擎
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json", // 指定编译命令 JSON 文件的路径(用于基于 CMake 或其他构建系统时提供编译信息)
"files.associations": { // 文件类型关联设置
"*.cpp": "cpp", // 将所有 .cpp 文件识别为 C++ 文件
"*.h": "cpp", // 将所有 .h 文件识别为 C++ 文件(兼容 C++ 头文件)
"vector": "cpp" // 将名为 vector 的文件/模块识别为 C++ 类型(通常是 STL 的一部分)
}
}
编写代码
main.cpp(固定结构,无需修改)
cpp
#include <d3d11.h> // Direct3D 11 头文件
#include <windows.h> // Win32 API 头文件
#include "imgui.h" // ImGui 核心头文件
#include "imgui_impl_win32.h" // ImGui Win32 平台绑定
#include "imgui_impl_dx11.h" // ImGui DirectX 11 渲染绑定
#include "Application.hpp" // 自定义 Application 逻辑
// 声明 ImGui 的 Win32 消息处理函数
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// 窗口过程函数,处理 Win32 消息
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// 让 ImGui 先处理输入相关的消息
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
return true;
switch (msg)
{
case WM_DESTROY: // 处理窗口关闭事件
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int main()
{
// 1. 创建 Win32 窗口
WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, "ImGuiExample", NULL};
RegisterClassEx(&wc);
HWND hwnd = CreateWindowEx(0, wc.lpszClassName, "ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
if (!hwnd)
{
return 1;
}
ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);
// 2. 初始化 DirectX 11 设备和交换链
DXGI_SWAP_CHAIN_DESC sd = {};
sd.BufferCount = 2;
sd.BufferDesc.Width = 0; // 让 DXGI 自动选择窗口大小
sd.BufferDesc.Height = 0;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 颜色格式
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = hwnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
UINT createDeviceFlags = 0;
D3D_FEATURE_LEVEL featureLevel;
const D3D_FEATURE_LEVEL featureLevelArray[2] = {D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0};
ID3D11Device *g_pd3dDevice = NULL;
ID3D11DeviceContext *g_pd3dDeviceContext = NULL;
IDXGISwapChain *g_pSwapChain = NULL;
if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext) != S_OK)
{
return 1;
}
// 创建渲染目标视图
ID3D11Texture2D *pBackBuffer = NULL;
g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
ID3D11RenderTargetView *g_mainRenderTargetView = NULL;
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_mainRenderTargetView);
pBackBuffer->Release();
// 3. 初始化 ImGui
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO();
(void)io;
ImGui::StyleColorsDark(); // 设置深色主题
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
// 4. 进入主循环
bool done = false;
while (!done)
{
MSG msg;
while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
done = true;
}
if (done)
break;
// 开始新的一帧 ImGui 渲染
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
// 渲染 UI
RenderUI();
// 渲染到屏幕
ImGui::Render();
float clearColor[4] = {0.0f, 0.0f, 0.0f, 1.0f}; // 黑色背景
g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL);
g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clearColor);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
g_pSwapChain->Present(1, 0); // 垂直同步
}
// 5. 清理资源
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
if (g_mainRenderTargetView)
{
g_mainRenderTargetView->Release();
}
if (g_pSwapChain)
{
g_pSwapChain->Release();
}
if (g_pd3dDeviceContext)
{
g_pd3dDeviceContext->Release();
}
if (g_pd3dDevice)
{
g_pd3dDevice->Release();
}
DestroyWindow(hwnd);
UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}
- 作用:创建窗口、初始化DirectX、处理消息循环
- 你的关注点:无需理解细节,这是框架的"发动机"
Application.hpp(你的创作空间)
cpp
// Application.hpp - 在此自由设计界面
#pragma once
#include <imgui.h>
void RenderUI()
{
ImGui::Begin("My First GUI");
// 示例:创建一个红色按钮
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 0, 0, 1));
if (ImGui::Button("Click for a Surprise"))
{
// 在此添加点击事件
}
ImGui::PopStyleColor();
ImGui::End();
}
开发技巧:
- 所有UI代码写在
RenderUI()
函数内 - 使用
ImGui::
开头的函数创建控件 - 按
Ctrl+Space
触发代码提示
构建与调试
一键编译
- 按下
Ctrl+Shift+B
启动编译(编译生成的二进制文件名为项目文件夹名) - 观察底部终端输出:
- 出现
Finished
表示成功 - 错误信息通常指向缺失文件或语法错误
- 出现
运行程序
- 方式一 :VSCode终端输入
./app.exe
- 方式二 :直接双击生成的
app.exe
预期效果 :
显示1280x800窗口,其中包含你设计的UI元素
进阶指引
修改窗口属性
在main.cpp
中搜索以下常量修改:
cpp
// 原值
CreateWindow(..., "标题", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, ...)
// 修改示例
CreateWindow(..., "新标题", WS_POPUP, 0, 0, 1920, 1080, ...)
学习资源推荐
- ImGui官方Demo源码 - 包含所有控件用法
- ImGui样式编辑器 - 定制界面外观