11.ImGui-加载字体和中文

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!

本次游戏没法给

内容参考于:微尘网络安全

上一个内容:10.ImGui-进度条

如下图现在的中文是乱码的,这个原因是没有加载支持中文的字体

加载字体的代码是

c++ 复制代码
ImGuiIO& io = ImGui::GetIO(); (void)io;  // 获取IO对象,管理输入输出
io.Fonts.xxx // xxx是加载字体的方式

如下图加载字体所有的方式,ttf是字体的文件类型

下图红框就是一个字体文件,我使用的是在内存中加载字体的方式,这样比较快,怎么把文件搞成内存里的东西?

在ImGui源码文件中,也有很多字体文件,如下图红框

下图红框的cpp是可以运行的,下图的cpp就可以把一个ttf文件搞成c++类,这样就能在内存中使用了

打开vs2022,点击下图红框新建项目

空项目

然后点击在文件资源管理器中打开文件夹,打开它的文件目录

把下图红框的cpp复制到刚刚创建的项目里

再把它拖到vs2022里

然后改成Release,然后重新生成

然后找到重新生成之后的文件,也就是下图红框的ceshiziti.exe文件,然后把字体文件复制过来

然后输入cmd按回车

然后运行指令 ceshiziti.exe -nocompress Test.ttf front_data > front.h,这样就会把Test.ttf搞成C++代码

front.h的内容

然后把这个front.h文件复制到我们的项目里

然后再把它拖到头文件里

如下图

然后引入这个front.h文件

加载字体的代码

c++ 复制代码
 ImGuiIO& io = ImGui::GetIO();

 // 创建字体配置结构体(ImFontConfig),用于自定义字体加载的各种参数
 // 该结构体包含字体大小、是否合并字体、字体数据所有权等配置项
 ImFontConfig ifc;

 // 设置字体数据的所有权:false表示字体数据(front_data_data)不由ImGui的字体图集(FontAtlas)管理
 // 含义:ImGui不会自动释放front_data_data指向的内存,需要用户在程序结束时手动释放
 // 反之,若设为true,ImGui会在销毁字体图集时自动释放该内存(适用于临时加载的字体数据)
 ifc.FontDataOwnedByAtlas = false;

 // 从内存中的TTF字体数据加载字体,并添加到字体图集中
 // 参数说明:
 // 1. (void*)front_data_data:指向内存中TTF字体文件数据的指针(二进制数据)
 // 2. front_data_size:TTF字体数据的大小(字节数),用于告诉ImGui需要读取多少数据
 // 3. 18.0f:字体的点大小(Point Size),是字体设计时的原始大小(与屏幕分辨率无关)
 // 4. &ifc:字体配置结构体指针,使用上面定义的自定义配置(如所有权设置)
 // 5. io.Fonts->GetGlyphRangesChineseFull():指定需要加载的中文字符集范围
 //    GetGlyphRangesChineseFull()会返回包含大部分简体/繁体中文的字符范围,确保中文能正常显示
 // 返回值:ImFont* 指向加载成功的字体对象,后续可通过该指针切换UI使用的字体
 ImFont* front = io.Fonts->AddFontFromMemoryTTF(
     (void*)front_data_data,
     front_data_size,
     18.0f,
     &ifc,
     io.Fonts->GetGlyphRangesChineseFull()
 );

效果图:前面带u8 表示使用utf8编码,我们加载的字体也是用的utf8编码,一个没加一个加了,可以看得出来效果,没加的中文还是乱码,加了的中文正常显示

完整代码:

c++ 复制代码
#include "main.h"  // 包含程序所需的头文件,其中声明了ImGui、DirectX等库的必要函数和类

// 全局变量:存储DirectX 11核心资源和窗口状态(整个程序共享)
static UINT                     g_ResizeWidth = 0, g_ResizeHeight = 0;
// 窗口调整大小时的新宽度和高度
// 当窗口大小改变时,WM_SIZE消息会将新尺寸存储到这两个变量中
// 主循环会检测这两个变量,当它们不为0时进行渲染目标的调整

static ID3D11Device* g_pd3dDevice = nullptr;
// Direct3D 11设备对象,是DirectX渲染的核心
// 负责创建所有的渲染资源,如纹理、缓冲区、渲染目标等
// 所有与硬件交互的渲染资源创建都需要通过该设备对象

static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr;
// Direct3D 11设备上下文,相当于渲染命令的执行者
// 用于设置渲染状态、绑定资源、执行绘制命令等操作
// 可以理解为向GPU发送渲染指令的接口

static IDXGISwapChain* g_pSwapChain = nullptr;
// 交换链对象,管理前后两个缓冲区实现双缓冲机制
// 前端缓冲区是正在显示的画面,后端缓冲区是正在渲染的画面
// 渲染完成后通过交换操作将后端缓冲区变为前端,避免画面闪烁

static ID3D11RenderTargetView* g_mainRenderTargetView = nullptr;
// 主渲染目标视图,是交换链后端缓冲区的视图
// 告诉GPU渲染结果应该输出到哪个缓冲区
// ImGui绘制的所有UI最终都会渲染到这个目标上

static bool                     g_SwapChainOccluded = false;
// 标记交换链是否被遮挡(如窗口被其他窗口完全覆盖)
// 当为true时可以暂停渲染以节省CPU和GPU资源
// 由Present函数的返回值判断并设置

// 声明ImGui的Win32消息处理函数(定义在imgui_impl_win32.cpp中)
// 该函数用于让ImGui处理鼠标、键盘等输入消息
// 参数说明:
// - hWnd: 窗口句柄,标识接收消息的窗口
// - msg: 消息类型,如WM_MOUSEMOVE(鼠标移动)、WM_KEYDOWN(按键按下)等
// - wParam: 消息参数1,存储与消息相关的附加信息
// - lParam: 消息参数2,存储与消息相关的附加信息
// 返回值:如果消息被ImGui处理则返回true,否则返回false
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// 自定义辅助函数:创建带提示的帮助标记
// 当鼠标悬停在"(?)"上时,会显示提示文本
// 参数:
// - desc: 要显示的提示文本内容
static void HelpMarker(const char* desc)
{
    ImGui::TextDisabled("(?)");  // 显示灰色的"(?)"作为帮助标记
    // 检查鼠标是否悬停在当前项目上,并开始绘制提示框
    if (ImGui::BeginItemTooltip())
    {
        // 设置文本自动换行的宽度(为字体大小的35倍)
        // 避免提示文本过长导致超出窗口范围
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
        ImGui::TextUnformatted(desc);  // 显示提示文本(无格式)
        ImGui::PopTextWrapPos();       // 恢复文本换行设置
        ImGui::EndTooltip();           // 结束提示框绘制
    }
}

// 窗口消息处理函数:处理所有与窗口相关的事件
// 包括窗口大小改变、关闭、鼠标键盘输入等
// 参数说明:
// - hWnd: 窗口句柄,标识当前接收消息的窗口
// - msg: 消息类型,Windows系统定义的消息编号
// - wParam: 消息参数1,具体含义取决于消息类型
// - lParam: 消息参数2,具体含义取决于消息类型
// 返回值:LRESULT类型,消息处理的结果
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    // 让ImGui先处理消息,优先处理UI相关的输入事件
    // 如果ImGui处理了该消息(如点击UI控件),则直接返回
    if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
        return true;

    // 根据消息类型进行不同处理
    switch (msg)
    {
    case WM_SIZE:  // 窗口大小改变事件
        // 如果是窗口最小化,则不需要调整渲染资源
        if (wParam == SIZE_MINIMIZED)
            return 0;
        // 从lParam中提取新的窗口宽度和高度
        // LOWORD宏获取lParam的低16位,存储宽度
        // HIWORD宏获取lParam的高16位,存储高度
        g_ResizeWidth = (UINT)LOWORD(lParam);
        g_ResizeHeight = (UINT)HIWORD(lParam);
        return 0;

    case WM_SYSCOMMAND:  // 系统命令事件(如ALT+空格调出窗口菜单)
        // 禁用ALT菜单,避免菜单弹出时遮挡ImGui控件
        // SC_KEYMENU是系统菜单命令,0xfff0用于屏蔽低位的扩展信息
        if ((wParam & 0xfff0) == SC_KEYMENU)
            return 0;
        break;  // 其他系统命令交给默认处理

    case WM_DESTROY:  // 窗口销毁事件(如点击关闭按钮)
        ::PostQuitMessage(0);  // 发送退出消息,主循环会捕获并结束程序
        return 0;
    }

    // 其他未处理的消息,交给Windows系统默认处理
    return ::DefWindowProcW(hWnd, msg, wParam, lParam);
}

// 创建渲染目标视图:将交换链的后台缓冲区绑定为渲染目标
// 渲染目标视图是GPU可以写入的资源视图
// 所有的渲染命令最终都会绘制到该渲染目标上
void CreateRenderTarget()
{
    ID3D11Texture2D* pBackBuffer = nullptr;  // 临时指针,用于获取后台缓冲区

    // 从交换链中获取后台缓冲区
    // 参数1:0表示获取第一个缓冲区(交换链通常有2个缓冲区)
    // 参数2:IID_ID3D11Texture2D是要获取的接口ID
    // 参数3:输出参数,接收后台缓冲区的指针
    g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));

    // 使用D3D设备创建渲染目标视图
    // 参数1:要绑定为渲染目标的纹理(这里是后台缓冲区)
    // 参数2:渲染目标视图的描述(nullptr表示使用默认设置)
    // 参数3:输出参数,接收创建的渲染目标视图
    g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView);

    // 释放临时的后台缓冲区指针
    // 渲染目标视图已经引用了该缓冲区,不需要再保留此指针
    pBackBuffer->Release();
}

// 清理渲染目标视图:释放资源,避免内存泄漏
// COM对象需要通过Release()方法释放,减少引用计数
// 当引用计数为0时,对象会被自动销毁
void CleanupRenderTarget()
{
    if (g_mainRenderTargetView)
    {
        g_mainRenderTargetView->Release();  // 释放渲染目标视图
        g_mainRenderTargetView = nullptr;   // 置空指针,避免野指针
    }
}

// 创建D3D11设备和交换链:初始化DirectX渲染环境
// 参数:
// - hWnd: 窗口句柄,渲染结果将显示在该窗口中
// 返回值:bool类型,true表示创建成功,false表示失败
bool CreateDeviceD3D(HWND hWnd)
{
    // 初始化交换链描述结构体,定义交换链的属性
    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(sd));  // 清空结构体,避免未初始化的内存导致错误

    // 配置交换链参数
    sd.BufferCount = 2;                   // 缓冲区数量,2表示双缓冲
    sd.BufferDesc.Width = 0;              // 缓冲区宽度,0表示自动匹配窗口宽度
    sd.BufferDesc.Height = 0;             // 缓冲区高度,0表示自动匹配窗口高度
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;  // 像素格式,32位RGBA(8位/通道)
    sd.BufferDesc.RefreshRate.Numerator = 60;  // 刷新率分子,60表示60Hz
    sd.BufferDesc.RefreshRate.Denominator = 1; // 刷新率分母,60/1=60Hz
    sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;  // 允许切换显示模式(窗口/全屏)
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;   // 缓冲区用途,作为渲染目标
    sd.OutputWindow = hWnd;               // 绑定的窗口,渲染结果显示到该窗口
    sd.SampleDesc.Count = 1;              // 多重采样数量,1表示无抗锯齿
    sd.SampleDesc.Quality = 0;            // 采样质量,0表示默认
    sd.Windowed = TRUE;                   // 窗口模式,TRUE表示窗口化,FALSE表示全屏
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;  // 交换效果,交换后丢弃后台缓冲区数据

    UINT createDeviceFlags = 0;  // 创建设备的标志
    // 调试模式开关,需要安装DirectX SDK才能使用
    // createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;

    D3D_FEATURE_LEVEL featureLevel;  // 存储实际支持的Direct3D特性级别(版本)
    // 支持的Direct3D版本列表,优先使用11.0,不支持则使用10.0
    const D3D_FEATURE_LEVEL featureLevelArray[2] = {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_0
    };

    // 创建设备、设备上下文和交换链
    HRESULT res = D3D11CreateDeviceAndSwapChain(
        nullptr,                       // 显卡适配器,nullptr表示使用默认显卡
        D3D_DRIVER_TYPE_HARDWARE,      // 驱动类型,硬件加速(使用GPU)
        nullptr,                       // 软件渲染模块,不需要则为nullptr
        createDeviceFlags,             // 创建设备的标志
        featureLevelArray,             // 支持的Direct3D版本列表
        2,                             // 版本列表的数量
        D3D11_SDK_VERSION,             // SDK版本,使用当前版本
        &sd,                           // 交换链描述结构体
        &g_pSwapChain,                 // 输出参数,接收创建的交换链
        &g_pd3dDevice,                 // 输出参数,接收创建的D3D设备
        &featureLevel,                 // 输出参数,接收实际支持的Direct3D版本
        &g_pd3dDeviceContext           // 输出参数,接收创建的设备上下文
    );

    // 如果硬件加速失败(如显卡不支持D3D11),尝试使用软件渲染(WARP驱动)
    if (res == DXGI_ERROR_UNSUPPORTED)
        res = D3D11CreateDeviceAndSwapChain(
            nullptr, D3D_DRIVER_TYPE_WARP,  // 软件渲染驱动
            nullptr, createDeviceFlags,
            featureLevelArray, 2,
            D3D11_SDK_VERSION, &sd,
            &g_pSwapChain, &g_pd3dDevice,
            &featureLevel, &g_pd3dDeviceContext
        );

    if (res != S_OK)  // 如果创建失败(S_OK表示成功)
        return false;

    CreateRenderTarget();  // 创建渲染目标视图
    return true;
}

// 清理D3D资源:释放所有DirectX相关对象
// 按照依赖顺序释放,避免资源引用冲突
void CleanupDeviceD3D()
{
    CleanupRenderTarget();  // 先清理渲染目标视图

    // 释放交换链
    if (g_pSwapChain)
    {
        g_pSwapChain->Release();
        g_pSwapChain = nullptr;
    }
    // 释放设备上下文
    if (g_pd3dDeviceContext)
    {
        g_pd3dDeviceContext->Release();
        g_pd3dDeviceContext = nullptr;
    }
    // 释放D3D设备
    if (g_pd3dDevice)
    {
        g_pd3dDevice->Release();
        g_pd3dDevice = nullptr;
    }
}

// 主函数:程序入口点,控制整个程序的生命周期
int main() {
    // DPI适配:解决高分辨率屏幕下UI模糊的问题
    ImGui_ImplWin32_EnableDpiAwareness();  // 开启ImGui对系统DPI的感知

    // 获取主显示器的DPI缩放比例
    // MonitorFromPoint获取主显示器的句柄
    // ImGui_ImplWin32_GetDpiScaleForMonitor计算该显示器的缩放比例
    float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(
        ::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)
    );

    // 创建Windows窗口:ImGui需要一个窗口作为载体来显示UI
    // 定义窗口类结构,描述窗口的基本属性
    WNDCLASSEXW wc = {
        sizeof(wc),                  // 结构体大小
        CS_CLASSDC,                  // 窗口类风格,使用专属设备上下文
        WndProc,                     // 窗口消息处理函数
        0L, 0L,                      // 额外的类数据和窗口数据(未使用)
        GetModuleHandle(nullptr),    // 程序实例句柄
        nullptr, nullptr, nullptr, nullptr,  // 图标、光标、背景画刷等(使用默认)
        L"ImGui Example",            // 窗口类名,用于标识该窗口类
        nullptr                      // 小图标(使用默认)
    };
    ::RegisterClassExW(&wc);  // 向系统注册窗口类

    // 创建窗口
    HWND hwnd = ::CreateWindowW(
        wc.lpszClassName,            // 窗口类名,必须与注册的类名一致
        L"Dear ImGui DirectX11 Example",  // 窗口标题栏显示的文本
        WS_OVERLAPPEDWINDOW,         // 窗口风格,标准可调整大小的窗口
        100, 100,                    // 窗口初始位置(屏幕左上角坐标)
        (int)(1280 * main_scale),    // 窗口宽度,根据DPI缩放
        (int)(800 * main_scale),     // 窗口高度,根据DPI缩放
        nullptr, nullptr,            // 父窗口句柄和菜单句柄(无)
        wc.hInstance, nullptr        // 程序实例句柄和额外数据(无)
    );

    // 初始化DirectX 11渲染环境
    if (!CreateDeviceD3D(hwnd))  // 如果创建失败
    {
        CleanupDeviceD3D();  // 清理已创建的资源
        ::UnregisterClassW(wc.lpszClassName, wc.hInstance);  // 注销窗口类
        return 1;  // 返回1表示程序异常退出
    }

    // 显示窗口(创建后窗口默认是隐藏的)
    ::ShowWindow(hwnd, SW_SHOWDEFAULT);
    ::UpdateWindow(hwnd);  // 刷新窗口,确保窗口立即显示

    // 初始化ImGui:创建UI上下文和配置
    IMGUI_CHECKVERSION();  // 检查ImGui版本,确保编译版本与运行时版本一致
    ImGui::CreateContext(); // 创建ImGui上下文,管理UI状态和资源
    // 获取ImGui的IO(输入输出)对象
// ImGuiIO是ImGui的核心配置对象,负责管理输入(鼠标、键盘、控制器)、输出(字体、显示尺寸等)
// 这里通过ImGui::GetIO()获取全局唯一的IO实例,后续字体配置需要通过它的Fonts成员(字体图集)进行
    ImGuiIO& io = ImGui::GetIO();

    // 创建字体配置结构体(ImFontConfig),用于自定义字体加载的各种参数
    // 该结构体包含字体大小、是否合并字体、字体数据所有权等配置项
    ImFontConfig ifc;

    // 设置字体数据的所有权:false表示字体数据(front_data_data)不由ImGui的字体图集(FontAtlas)管理
    // 含义:ImGui不会自动释放front_data_data指向的内存,需要用户在程序结束时手动释放
    // 反之,若设为true,ImGui会在销毁字体图集时自动释放该内存(适用于临时加载的字体数据)
    ifc.FontDataOwnedByAtlas = false;

    // 从内存中的TTF字体数据加载字体,并添加到字体图集中
    // 参数说明:
    // 1. (void*)front_data_data:指向内存中TTF字体文件数据的指针(二进制数据)
    // 2. front_data_size:TTF字体数据的大小(字节数),用于告诉ImGui需要读取多少数据
    // 3. 18.0f:字体的点大小(Point Size),是字体设计时的原始大小(与屏幕分辨率无关)
    // 4. &ifc:字体配置结构体指针,使用上面定义的自定义配置(如所有权设置)
    // 5. io.Fonts->GetGlyphRangesChineseFull():指定需要加载的中文字符集范围
    //    GetGlyphRangesChineseFull()会返回包含大部分简体/繁体中文的字符范围,确保中文能正常显示
    // 返回值:ImFont* 指向加载成功的字体对象,后续可通过该指针切换UI使用的字体
    ImFont* front = io.Fonts->AddFontFromMemoryTTF(
        (void*)front_data_data,
        front_data_size,
        18.0f,
        &ifc,
        io.Fonts->GetGlyphRangesChineseFull()
    );

    // 配置ImGui功能
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;  // 开启键盘导航(方向键、Tab等)
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;   // 开启游戏手柄导航

    // 设置UI缩放:适配高DPI屏幕,避免UI元素过小
    ImGuiStyle& style = ImGui::GetStyle();
    style.ScaleAllSizes(main_scale);  // 缩放所有UI元素的大小
    style.FontScaleDpi = main_scale;  // 缩放字体大小

    // 初始化ImGui后端:连接ImGui与系统和渲染API
    ImGui_ImplWin32_Init(hwnd);       // 初始化Win32后端,处理窗口消息和输入
    ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);  // 初始化DX11后端,负责渲染UI

    // 程序状态变量:控制UI显示和存储用户输入数据
    bool show_demo_window = true;    // 是否显示ImGui演示窗口(未使用)
    bool show_another_window = false; // 是否显示另一个窗口(未使用)
    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); // 窗口背景色(浅蓝色)
    ImVec4 seBan = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);       // 用于按钮颜色的变量

    // 输入框缓冲区:存储用户输入的文本
    char name[1024] = "";    // 用户名输入缓冲区,容量1024字节
    char pass[1024] = "";    // 密码输入缓冲区,容量1024字节
    char text[1024] = "";    // 备用文本缓冲区(未使用)

    // 多行输入框配置
    const size_t BUF_SIZE = 1024;                // 缓冲区最大容量
    char input_text[BUF_SIZE] = "1111...\n22222\n333";  // 初始文本内容

    // 主循环:程序的核心,持续运行直到用户关闭窗口
    bool done = false;  // 控制循环是否结束的标志
    while (!done)
    {
        // 处理窗口消息:从消息队列中获取并处理所有待处理消息
        MSG msg;
        // PeekMessage非阻塞地获取消息,PM_REMOVE表示获取后从队列中移除
        while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE))
        {
            ::TranslateMessage(&msg);  // 翻译消息(如将键盘扫描码转换为字符)
            ::DispatchMessage(&msg);   // 将消息分发到窗口的消息处理函数(WndProc)
            if (msg.message == WM_QUIT)  // 如果收到退出消息
                done = true;  // 标记循环结束
        }
        if (done)
            break;  // 退出主循环

        // 处理窗口遮挡:如果窗口被完全遮挡,减少渲染频率以节省资源
        if (g_SwapChainOccluded &&
            g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED)
        {
            ::Sleep(10);  // 休眠10毫秒
            continue;     // 跳过本次循环,不进行渲染
        }
        g_SwapChainOccluded = false;  // 重置遮挡状态

        // 处理窗口大小调整:当窗口大小改变时,调整渲染目标
        if (g_ResizeWidth != 0 && g_ResizeHeight != 0)
        {
            CleanupRenderTarget();  // 先清理旧的渲染目标

            // 调整交换链缓冲区大小以匹配新的窗口尺寸
            g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight,
                DXGI_FORMAT_UNKNOWN, 0);
            g_ResizeWidth = g_ResizeHeight = 0;  // 重置尺寸变量
            CreateRenderTarget();  // 创建新的渲染目标

        }

        // 开始ImGui新帧:准备绘制UI
        ImGui_ImplDX11_NewFrame();  // DX11后端准备新帧
        ImGui_ImplWin32_NewFrame(); // Win32后端准备新帧(处理输入)
        ImGui::NewFrame();          // ImGui核心准备,开始定义UI

        // 定义UI界面:创建一个名为"我的IMGui"的窗口
        bool is_window_open = true;  // 控制窗口是否显示的标志
        // ImGui::Begin()参数说明:
        // - 第一个参数:窗口标题,同时作为窗口的唯一标识
        // - 第二个参数:控制窗口是否显示的指针,关闭窗口时会设为false
        // - 第三个参数:窗口标志(默认为0,使用默认窗口样式)
        // 带中文的字符前面要带着u8
      // 开始创建一个ImGui窗口,与ImGui::End()配对使用,中间的代码定义窗口内容
        // 函数作用:初始化窗口状态(位置、大小、标题等),并准备绘制窗口内的UI元素
        // 返回值:bool类型,若为true表示窗口处于激活状态(可绘制内容);若为false表示窗口被最小化或关闭,此时应跳过绘制直接调用ImGui::End()
                ImGui::Begin(
                    u8"我的IMGui",  // 窗口标题(显示在标题栏),同时作为窗口的唯一标识
                    // u8前缀表示字符串采用UTF-8编码,确保中文"我的IMGui"能正确显示(避免乱码)
                    // 注意:不同窗口的标题需唯一,否则ImGui会视为同一个窗口
                    &is_window_open // 指向bool变量的指针,用于控制窗口是否显示
                    // 当用户点击窗口右上角的关闭按钮时,ImGui会自动将*is_window_open设为false
                    // 若传入nullptr,则窗口无法通过UI关闭(只能通过代码控制)
        // 可选参数(此处未使用):窗口标志(如ImGuiWindowFlags_NoTitleBar去除标题栏等)
        );

        // 显示自动换行的长文本
        ImGui::TextWrapped(
            "This 521 "
            "aiamaiamaiamaiamaiamaiamaiamaiamaiamaiamaiam");

        // 显示带颜色的文本
        // ImGui::TextColored()参数:
        // - 第一个参数:ImVec4类型的颜色(RGBA,每个分量0.0f-1.0f)
        // - 后续参数:格式化字符串和参数(与printf类似)
        ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pin中文k");  // 粉色文本
        ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");  // 黄色文本

        // 显示带颜色的文本和帮助标记,并在同一行
        ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink2");
        ImGui::SameLine();  // 让下一个控件与当前控件在同一行
        ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow2");
        ImGui::SameLine();
        HelpMarker("52am");  // 显示帮助标记,鼠标悬停显示"52am"

        // 颜色编辑控件:允许用户选择颜色
        // ImGui::ColorEdit3()参数:
        // - 第一个参数:控件标签
        // - 第二个参数:颜色变量的指针(需要转换为float*)
        // 选择的颜色会存储到seBan变量中
        ImGui::ColorEdit3("clear color", (float*)&seBan);

        // 修改按钮样式:临时改变按钮在不同状态下的颜色
        // ImGui::PushStyleColor()参数:
        // - 第一个参数:要修改的颜色类型(ImGuiCol_开头的枚举)
        // - 第二个参数:新的颜色值(ImVec4类型)
        ImGui::PushStyleColor(ImGuiCol_Button, seBan);           // 按钮正常状态颜色
        ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 1.0f,0.0f,0.0f,1.0f }); // 鼠标悬停状态
        ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.0f,1.0f,0.0f,1.0f });  // 鼠标点击状态

        // 创建按钮:ImGui::Button()返回bool值,表示按钮是否被点击
        if (ImGui::Button("anNiu")) {
            // 按钮被点击时,显示黄色文本"dianjianniu"
            ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "dianjianniu");
        }

        // 恢复样式:弹出之前压入的3个颜色设置
        // 必须与PushStyleColor的数量一致,否则会影响其他UI元素
        ImGui::PopStyleColor(3);

        // 复选框:允许用户切换选项的开关状态
        // ImGui::Checkbox()参数:
        // - 第一个参数:复选框标签
        // - 第二个参数:bool变量的指针,存储复选框的状态(true=勾选,false=未勾选)
        static bool check = true;
        static bool check1 = true;
        static bool check2 = false;
        static bool check3 = true;
        ImGui::Checkbox("checkbox", &check);
        ImGui::Checkbox("checkbox1", &check1);
        ImGui::Checkbox("checkbox2", &check2);
        ImGui::Checkbox("checkbox3", &check3);

        // 单选框:从多个选项中选择一个
        // ImGui::RadioButton()参数:
        // - 第一个参数:单选框标签
        // - 第二个参数:当前选中项的索引指针
        // - 第三个参数:当前单选框的索引值
        static int radio_selected = 0;  // 存储选中项的索引
        ImGui::RadioButton("radio a", &radio_selected, 0); ImGui::SameLine();
        ImGui::RadioButton("radio b", &radio_selected, 1); ImGui::SameLine();
        ImGui::RadioButton("radio c", &radio_selected, 2);

        // 输入框:接收用户文本输入
        ImGui::Text("name");  // 显示"name"作为输入框的标签
        ImGui::SameLine();    // 与输入框在同一行

        // ImGui输入框的标识规则详解:
        // 1. 格式为"标签##标识符":显示"标签",但内部用"标识符"区分不同控件
        // 2. 格式为"##标识符":不显示标签,仅用"标识符"作为内部标识
        // 3. 无"##":整个字符串既作为显示标签,也作为内部标识
        // 这里"##name"表示:不显示标签,内部用"name"作为标识
        ImGui::InputText("##name", name, IM_ARRAYSIZE(name));

        ImGui::Text("pass");  // 显示"pass"作为密码框的标签
        ImGui::SameLine();
        // 密码输入框:ImGuiInputTextFlags_Password标志使输入内容显示为*
        ImGui::InputText("##pass", pass, IM_ARRAYSIZE(pass), ImGuiInputTextFlags_Password);
        ImGui::InputText("p2ass", pass, IM_ARRAYSIZE(pass), ImGuiInputTextFlags_Password);

        // 带提示的输入框:当输入框为空时显示提示文本
        char hint_text[1024] = "mo ren ti shi";  // 提示文本
        ImGui::InputTextWithHint("##InputTextWithHint", hint_text,
            name, IM_ARRAYSIZE(name));

        // 多行输入框:允许输入多行文本
        ImGui::InputTextMultiline(
            "##MultiLineInput",  // 内部标识(不显示标签)
            input_text,          // 存储文本的缓冲区
            BUF_SIZE,            // 缓冲区最大容量
            ImVec2(0, 200)       // 输入框尺寸(宽度0表示自适应窗口,高度200像素)
        );

        // 加static让f变成静态变量,静态变量在函数中只会执行一次
        // 第一次执行当前函数会执行 static float f = 0.0f; 这一行代码,第二次执行当前函数时会跳过 static float f = 0.0f;这一行代码
        // 这样就能修改f的值后不会被重新赋值成0了
        static float f = 0.0f;
        // 滑块
        ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
        ImGui::SliderFloat("##float", &f, 0.0f, 1.0f);

        // progress当前进度,progress_dir进度范围
        static float progress = 0.0f, progress_dir = 1.0f;
        progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
        // 第一个参数传当前进度,一个小数,第二个参数是进度条的长和高,第三个参数进度条里的描述
        ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f), "jinduxinxi");
        ImGui::ProgressBar(progress, ImVec2(300.0f, 20.0f));
        ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
        ImGui::Text("Progress Bar");


        ImGui::End();  // 结束窗口定义(必须与ImGui::Begin配对使用)

        // 渲染UI:将定义的UI绘制到屏幕上
        ImGui::Render();  // 生成绘制命令列表

        // 计算背景色(考虑透明度)
        const float clear_color_with_alpha[4] = {
            clear_color.x * clear_color.w,
            clear_color.y * clear_color.w,
            clear_color.z * clear_color.w,
            clear_color.w
        };

        // 设置渲染目标:告诉GPU接下来的渲染输出到主渲染目标
        g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
        // 清空渲染目标:用背景色填充屏幕,清除上一帧的内容
        g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView,
            clear_color_with_alpha);
        // 渲染ImGui的UI:执行绘制命令
        ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());

        // 显示画面:交换前后缓冲区,将渲染好的画面显示到屏幕上
        // Present()参数:
        // - 第一个参数:1表示开启垂直同步(VSync),0表示关闭
        // - 第二个参数:交换标志(0表示默认行为)
        HRESULT hr = g_pSwapChain->Present(1, 0);  // 开启垂直同步
        // 检查交换链是否被遮挡,用于下一次循环的优化
        g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED);
    }

    // 程序退出:清理所有资源
    // 关闭ImGui后端
    ImGui_ImplDX11_Shutdown();
    ImGui_ImplWin32_Shutdown();
    ImGui::DestroyContext();  // 销毁ImGui上下文

    // 清理D3D资源
    CleanupDeviceD3D();
    // 销毁窗口和窗口类
    ::DestroyWindow(hwnd);
    ::UnregisterClassW(wc.lpszClassName, wc.hInstance);

    return 0;  // 程序正常退出
}

相关推荐
浩浩乎@3 小时前
【openGLES】纹理
c++·opengles
叫我龙翔3 小时前
【设计模式】从游戏角度开始了解设计模式 --- 抽象工厂模式
c++·游戏·设计模式
李游Leo3 小时前
Rust 开发环境安装与 crates.io 国内源配置(Windows / macOS / Linux 全流程)
windows·macos·rust
青草地溪水旁3 小时前
设计模式(C++)详解—单例模式(1)
c++·单例模式
小王不爱笑1324 小时前
Java基础知识(十四)
java·windows·python
HMBBLOVEPDX4 小时前
C++(深拷贝和浅拷贝)
开发语言·c++·浅拷贝和深拷贝
sc_yhsheng4 小时前
18j621-3通风天窗图集pdf(免费高清版)
windows·pdf
UrSpecial5 小时前
Linux线程
linux·开发语言·c++
郝学胜-神的一滴5 小时前
深入浅出 C++20:新特性与实践
开发语言·c++·程序人生·算法·c++20