免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
本次游戏没法给
内容参考于:微尘网络安全
上一个内容:4.ImGui-静态文本框
按钮的代码
ImGui::Button("anNiu")
修改按钮的颜色,鼠标放上去的颜色,鼠标点击的颜色,鼠标未放上去的颜色
// ImGui中通过PushStyleColor()临时修改按钮在不同状态下的颜色
// 注意:每次PushStyleColor()后必须用PopStyleColor()恢复默认样式,否则会影响后续UI元素
// 1. 修改按钮"正常状态"(未被鼠标悬停、未被点击)的背景色
// 参数1:ImGuiCol_Button - 指定修改"按钮正常状态"的颜色
// 参数2:{1.0f, 1.0f, 0.0f, 1.0f} - RGBA颜色值(每个分量范围0.0f~1.0f)
// R=1.0f(红色满值)、G=1.0f(绿色满值)、B=0.0f(蓝色无)→ 混合为黄色
// A=1.0f(透明度100%,完全不透明)
ImGui::PushStyleColor(ImGuiCol_Button, { 1.0f,1.0f,0.0f, 1.0f });
// 2. 修改按钮"鼠标悬停状态"(鼠标放在按钮上但未点击)的背景色
// 参数1:ImGuiCol_ButtonHovered - 指定修改"按钮被悬停时"的颜色
// 参数2:{1.0f, 0.0f, 0.0f, 1.0f} → 红色(R满值,G、B无),完全不透明
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 1.0f,0.0f,0.0f, 1.0f });
// 3. 修改按钮"激活状态"(鼠标按下按钮但未松开)的背景色
// 参数1:ImGuiCol_ButtonActive - 指定修改"按钮被点击时"的颜色
// 参数2:{0.0f, 1.0f, 0.0f, 1.0f} → 绿色(G满值,R、B无),完全不透明
ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.0f,1.0f,0.0f, 1.0f });
完整代码
#include "main.h" // 包含程序所需的头文件(包含ImGui、DirectX等声明,具体内容在main.h中定义)
// 全局变量:存储DirectX 11核心资源和窗口状态(整个程序共享,方便各函数访问)
static UINT g_ResizeWidth = 0, g_ResizeHeight = 0; // 窗口调整大小时的新宽高(由消息处理函数记录,主循环处理)
static ID3D11Device* g_pd3dDevice = nullptr; // D3D11设备对象(核心!用于创建纹理、缓冲区等渲染资源)
static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr; // D3D11设备上下文(用于执行绘制、清空等渲染命令)
static IDXGISwapChain* g_pSwapChain = nullptr; // 交换链(双缓冲区机制,避免画面闪烁,负责显示渲染结果)
static ID3D11RenderTargetView* g_mainRenderTargetView = nullptr; // 主渲染目标视图(绑定交换链的后台缓冲区,ImGui绘制的内容会输出到这里)
static bool g_SwapChainOccluded = false; // 标记交换链是否被遮挡(如窗口被覆盖,用于优化性能)
// 声明ImGui的Win32消息处理函数(来自imgui_impl_win32.cpp,用于让ImGui处理鼠标/键盘输入)
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static void HelpMarker(const char* desc)
{
ImGui::TextDisabled("(?)");
if (ImGui::BeginItemTooltip())
{
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
// 窗口消息处理函数:处理所有窗口事件(如点击、关闭、调整大小等)
// 参数:
// - hWnd:窗口句柄(标识当前窗口)
// - msg:消息类型(如WM_SIZE表示窗口大小改变)
// - wParam:消息附加参数(如WM_SIZE中表示 resize 类型)
// - lParam:消息附加参数(如WM_SIZE中存储新的宽高)
// 返回值:LRESULT类型(消息处理结果,0表示成功处理)
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// 让ImGui先处理消息(如果是ImGui的UI控件触发的事件,优先由ImGui处理)
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
return true; // ImGui已处理,直接返回
// 根据消息类型处理不同事件
switch (msg)
{
case WM_SIZE: // 窗口大小改变事件
if (wParam == SIZE_MINIMIZED) // 如果是窗口最小化,无需处理渲染相关
return 0;
// 从lParam中提取新的窗口尺寸:低16位是宽度,高16位是高度
g_ResizeWidth = (UINT)LOWORD(lParam); // 记录新宽度
g_ResizeHeight = (UINT)HIWORD(lParam); // 记录新高度
return 0;
case WM_SYSCOMMAND: // 系统命令事件(如ALT+空格调出窗口菜单)
// 禁用ALT菜单(避免菜单遮挡ImGui控件,影响操作体验)
if ((wParam & 0xfff0) == SC_KEYMENU)
return 0;
break; // 其他系统命令交给默认处理
case WM_DESTROY: // 窗口销毁事件(如点击关闭按钮)
::PostQuitMessage(0); // 发送退出消息,主循环会捕获并结束程序
return 0;
}
// 其他未处理的消息,交给Windows系统默认处理
return ::DefWindowProcW(hWnd, msg, wParam, lParam);
}
// 创建渲染目标视图:将交换链的后台缓冲区绑定为渲染目标(ImGui绘制的内容会输出到这里)
void CreateRenderTarget()
{
ID3D11Texture2D* pBackBuffer = nullptr; // 临时存储交换链的后台缓冲区
// 从交换链获取后台缓冲区(参数0表示第一个缓冲区,IID_ID3D11Texture2D指定缓冲区类型)
g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
// 用D3D设备创建渲染目标视图(将后台缓冲区转换为可渲染的目标)
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView);
// 释放临时缓冲区(渲染目标视图已引用它,无需保留此指针)
pBackBuffer->Release();
}
// 清理渲染目标视图:释放资源,避免内存泄漏
void CleanupRenderTarget()
{
// 释放渲染目标视图(COM对象需调用Release()减少引用计数,为0时自动释放内存)
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位色,含透明度)
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; // 创建设备的标志(0=默认,调试时可加D3D11_CREATE_DEVICE_DEBUG)
// createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; // 调试模式(需安装DirectX SDK)
D3D_FEATURE_LEVEL featureLevel; // 存储实际支持的D3D版本(如11.0、10.0)
// 支持的D3D版本列表(优先11.0,不支持则用10.0)
const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, };
// 创建设备、设备上下文和交换链(DirectX核心函数)
HRESULT res = D3D11CreateDeviceAndSwapChain(
nullptr, D3D_DRIVER_TYPE_HARDWARE, // 使用硬件加速(显卡渲染)
nullptr, createDeviceFlags, // 无软件渲染模块,创建标志
featureLevelArray, 2, // 支持的D3D版本列表及数量
D3D11_SDK_VERSION, &sd, // SDK版本,交换链描述
&g_pSwapChain, &g_pd3dDevice, // 输出交换链和设备
&featureLevel, &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(); // 先清理渲染目标
// 释放COM对象(按依赖顺序释放,避免资源冲突)
if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = nullptr; }
if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = nullptr; }
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; }
}
// 主函数:程序入口,控制整个程序的生命周期
int main() {
// -------------------------- 步骤1:DPI适配(解决高分辨率屏幕UI模糊问题) --------------------------
ImGui_ImplWin32_EnableDpiAwareness(); // 开启ImGui对系统DPI的感知
// 获取主显示器的DPI缩放比例(如4K屏幕可能为2.0,1080P可能为1.0)
float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(
::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY) // 获取主显示器
);
// -------------------------- 步骤2:创建Windows窗口(ImGui需要依附的窗口载体) --------------------------
// 定义窗口类(描述窗口的基本属性,如消息处理函数、图标等)
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, // 初始位置(屏幕左上角x=100,y=100)
(int)(1280 * main_scale), // 宽度(1280 * DPI缩放,适配高分辨率)
(int)(800 * main_scale), // 高度(800 * DPI缩放)
nullptr, nullptr, // 父窗口、菜单(无)
wc.hInstance, nullptr // 程序实例、额外参数
);
// -------------------------- 步骤3:初始化DirectX 11(创建渲染环境) --------------------------
if (!CreateDeviceD3D(hwnd)) // 调用函数创建D3D设备和交换链,失败则清理资源并退出
{
CleanupDeviceD3D();
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
return 1; // 返回1表示程序异常退出
}
// 显示窗口(创建后默认隐藏,需手动显示)
::ShowWindow(hwnd, SW_SHOWDEFAULT);
::UpdateWindow(hwnd); // 刷新窗口,确保立即显示
// -------------------------- 步骤4:初始化ImGui(配置UI环境) --------------------------
IMGUI_CHECKVERSION(); // 检查ImGui版本(确保编译版本与运行时一致)
ImGui::CreateContext(); // 创建ImGui上下文(UI的"全局环境")
ImGuiIO& io = ImGui::GetIO(); (void)io; // 获取IO对象(管理输入输出,如键盘、帧率)
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 开启键盘导航(方向键、Tab操作UI)
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // 开启手柄导航(支持游戏手柄操作)
// -------------------------- 步骤5:设置UI缩放(适配DPI,避免高分辨率下UI过小) --------------------------
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(main_scale); // 缩放所有UI元素(按钮、文本等)
style.FontScaleDpi = main_scale; // 缩放字体大小
// -------------------------- 步骤6:初始化ImGui后端(连接ImGui与系统/渲染API) --------------------------
ImGui_ImplWin32_Init(hwnd); // 初始化Win32后端(处理窗口消息、输入)
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); // 初始化DX11后端(负责渲染UI)
// -------------------------- 步骤7:程序状态变量(控制UI显示) --------------------------
bool show_demo_window = true; // 是否显示ImGui演示窗口
bool show_another_window = false; // 是否显示"另一个窗口"
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); // 窗口背景色(浅蓝色)
// -------------------------- 步骤8:主循环(程序的核心,持续运行直到退出) --------------------------
bool done = false; // 控制循环是否结束(true=退出)
while (!done)
{
// -------------------------- 8.1 处理窗口消息(如关闭、点击等) --------------------------
MSG msg; // 存储消息的结构体
// 从消息队列中获取消息(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; // 退出循环
// -------------------------- 8.2 处理窗口遮挡(优化性能) --------------------------
// 如果交换链被遮挡(如窗口被覆盖),且确认遮挡状态:
if (g_SwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED)
{
::Sleep(10); // 休眠10ms,减少CPU占用
continue; // 跳过本次循环,不渲染
}
g_SwapChainOccluded = false; // 重置遮挡状态
// -------------------------- 8.3 处理窗口大小调整(避免画面拉伸) --------------------------
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(); // 创建新的渲染目标(适配新尺寸)
}
// -------------------------- 8.4 开始ImGui新帧(准备绘制UI) --------------------------
ImGui_ImplDX11_NewFrame(); // DX11后端准备新帧
ImGui_ImplWin32_NewFrame(); // Win32后端准备新帧
ImGui::NewFrame(); // ImGui核心准备(通知ImGui可以开始定义UI了)
// -------------------------- 8.5 定义UI界面(核心:这里是你要显示的UI) --------------------------
/**
ImGui::Begin()函数说明:
函数声明:bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);
参数:
- name:窗口标题(唯一标识,相同标题会合并窗口)
- p_open:控制窗口是否显示的指针(关闭窗口时会将其设为false)
- flags:窗口标志(组合使用,如禁用标题栏、禁止移动等)
*/
bool i = true; // 控制窗口是否显示(true=显示)
// 创建一个自定义窗口:标题为"我的IMGui",禁止标题栏(NoTitleBar)和移动(NoMove)
ImGui::Begin("我的IMGui", &i);
// 这里可以添加其他UI控件(如按钮、文本等),目前是空窗口
// 例如:ImGui::Text("这是我的第一个ImGui窗口!");
// 长文本
ImGui::TextWrapped(
"This 521 "
"aiamaiamaiamaiamaiamaiamaiamaiamaiamaiamaiam");
ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
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();
// 鼠标悬浮上去会显示悬浮文本框,悬浮文本框会显示52am
HelpMarker("52am");
// ImGui中通过PushStyleColor()临时修改按钮在不同状态下的颜色
// 注意:每次PushStyleColor()后必须用PopStyleColor()恢复默认样式,否则会影响后续UI元素
// 1. 修改按钮"正常状态"(未被鼠标悬停、未被点击)的背景色
// 参数1:ImGuiCol_Button - 指定修改"按钮正常状态"的颜色
// 参数2:{1.0f, 1.0f, 0.0f, 1.0f} - RGBA颜色值(每个分量范围0.0f~1.0f)
// R=1.0f(红色满值)、G=1.0f(绿色满值)、B=0.0f(蓝色无)→ 混合为黄色
// A=1.0f(透明度100%,完全不透明)
ImGui::PushStyleColor(ImGuiCol_Button, { 1.0f,1.0f,0.0f, 1.0f });
// 2. 修改按钮"鼠标悬停状态"(鼠标放在按钮上但未点击)的背景色
// 参数1:ImGuiCol_ButtonHovered - 指定修改"按钮被悬停时"的颜色
// 参数2:{1.0f, 0.0f, 0.0f, 1.0f} → 红色(R满值,G、B无),完全不透明
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 1.0f,0.0f,0.0f, 1.0f });
// 3. 修改按钮"激活状态"(鼠标按下按钮但未松开)的背景色
// 参数1:ImGuiCol_ButtonActive - 指定修改"按钮被点击时"的颜色
// 参数2:{0.0f, 1.0f, 0.0f, 1.0f} → 绿色(G满值,R、B无),完全不透明
ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.0f,1.0f,0.0f, 1.0f });
if (ImGui::Button("anNiu")) {
// 点击按钮执行的代码
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "dianjianniu");
}
ImGui::PopStyleColor(3);
ImGui::End(); // 结束窗口定义(必须与Begin配对,否则崩溃)
// -------------------------- 8.6 渲染UI(将定义的UI绘制到屏幕) --------------------------
ImGui::Render(); // 生成绘制命令(将UI转换为显卡可执行的指令)
// 计算背景色(考虑透明度:clear_color.w是透明度,乘以RGB值)
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
};
// 设置渲染目标(告诉显卡:接下来的绘制输出到主渲染目标)
g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
// 清空屏幕(用背景色填充,避免上一帧画面残留)
g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
// 渲染ImGui的UI(执行绘制命令,将UI画到屏幕)
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
// -------------------------- 8.7 显示画面(交换前后缓冲区,展示渲染结果) --------------------------
// Present函数:交换前后缓冲区(后台缓冲区是刚渲染的画面,前台是正在显示的)
// 参数1:1=开启垂直同步(VSync,防止画面撕裂,帧率与显示器一致);0=关闭(帧率更高)
HRESULT hr = g_pSwapChain->Present(1, 0); // 开启垂直同步
// HRESULT hr = g_pSwapChain->Present(0, 0); // 关闭垂直同步
// 检查交换链是否被遮挡(用于后续优化)
g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED);
}
// -------------------------- 步骤9:程序退出,清理资源 --------------------------
// 关闭ImGui后端
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext(); // 销毁ImGui上下文
// 清理D3D资源
CleanupDeviceD3D();
// 销毁窗口和窗口类
::DestroyWindow(hwnd);
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
return 0; // 程序正常退出
}