【C++】ImGui:VSCode下的无依赖轻量GUI开发

本教程将手把手带您用纯原生方式构建ImGui应用,无需CMake/第三方库。您将全程明了自己每个操作的意义,特别适合首次接触GUI开发的新手。

环境配置

安装VSCode

  • 作用:轻量级代码编辑器,提供智能提示
  • 操作
    1. 官网下载安装包 → 默认选项安装
    2. 安装后打开,按下Ctrl+Shift+X安装"C/C++ Extension Pack"

配置MinGW

  • 作用:提供Windows下的GCC编译环境
  • 操作
    1. 访问WinLibs下载MinGW-W64 GCC 14.2.0 + LLVM/Clang/LLD/LLDB 19.1.7的Release包
    2. 解压到C:\mingw64(路径不可含中文)
    3. 右键开始菜单 → 系统 → 高级系统设置 → 环境变量 → 在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源码

精准获取必要文件

  1. 访问Imgui的GitHub仓库
  2. 下载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, ...)

学习资源推荐

相关推荐
lydxwj2 小时前
可视化编辑器选择
编辑器
lisw053 小时前
PyCharm使用中文版还是英文版较好?出于编程能力进阶和编程复杂性提高的考虑。
ide·python·pycharm
害人终害己3 小时前
IDE集成开发环境MyEclipse中安装SVN
ide·svn·myeclipse
成功助力英语中国话14 小时前
visual studio 2022中如何添加项目到解决方案中
前端·ide·visual studio
儒雅芝士16 小时前
修改Jupyter默认文件路径
ide·python·jupyter
马立杰18 小时前
VSCode知名主题带毒 安装量900万次
vscode
酒吧舞男20 小时前
Ubuntu20.04双系统安装及软件安装(五):VSCode
ide·vscode·编辑器
keep one's resolveY21 小时前
VsCode使用
ide·vscode·编辑器
Assists_fung21 小时前
Mac上安装Pycharm
ide·macos·pycharm
独隅21 小时前
VSCode详细安装步骤,适用于 Windows/macOS/Linux 系统
windows·vscode·macos