C++利用ImGUI繪制D3D外部菜單
ImGUI 它是與平臺(tái)無(wú)關(guān)的C++輕量級(jí)跨平臺(tái)圖形界面庫(kù),沒(méi)有任何第三方依賴,可以將ImGUI的源碼直接加到項(xiàng)目中使用,該框架通常會(huì)配合特定的D3Dx9等圖形開(kāi)發(fā)工具包一起使用,ImGUI常用來(lái)實(shí)現(xiàn)進(jìn)程內(nèi)的菜單功能,而有些輔助開(kāi)發(fā)作者也會(huì)使用該框架開(kāi)發(fā)菜單頁(yè)面,總體來(lái)說(shuō)這是一個(gè)很不錯(cuò)的繪圖庫(kù),如下將公開(kāi)新版ImGUI如何實(shí)現(xiàn)繪制外部菜單的功能。
ImGUI官方下載地址:https://github.com/ocornut/imgui/releases
在使用ImGUI頁(yè)面之前需要先來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的附著功能,即如何將一個(gè)窗體附著到另一個(gè)窗體之上,其實(shí)代碼很簡(jiǎn)單,如下所示當(dāng)用戶輸入進(jìn)程PID時(shí),會(huì)自動(dòng)跟隨窗體并附著在窗體頂部。
#include <Windows.h> #include <iostream> struct handle_data { unsigned long process_id; HWND best_handle; }; // By: LyShark BOOL IsMainWindow(HWND handle) { return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle); } BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) { // By: LyShark handle_data& data = *(handle_data*)lParam; unsigned long process_id = 0; GetWindowThreadProcessId(handle, &process_id); if (data.process_id != process_id || !IsMainWindow(handle)) { return TRUE; } data.best_handle = handle; return FALSE; } // By: LyShark HWND FindMainWindow(unsigned long process_id) { handle_data data; data.process_id = process_id; data.best_handle = 0; EnumWindows(EnumWindowsCallback, (LPARAM)&data); return data.best_handle; } int main(int argc, char* argv[]) { DWORD pid = 28396; std::cout << "輸入進(jìn)程PID: " << std::endl; std::cin >> pid; // 獲取屏幕寬和高 int iWidth = ::GetSystemMetrics(SM_CXSCREEN); int iHeight = ::GetSystemMetrics(SM_CYSCREEN); // 根據(jù)PID尋找游戲窗口 HWND hwnd = FindMainWindow(pid); while (1) { SetTimer(hwnd, 1, 150, NULL); // 實(shí)現(xiàn)透明必須設(shè)置WS_EX_LAYERED標(biāo)志 LONG lWinStyleEx = GetWindowLong(hwnd, GWL_EXSTYLE); lWinStyleEx = lWinStyleEx | WS_EX_LAYERED; SetWindowLong(hwnd, GWL_EXSTYLE, lWinStyleEx); SetLayeredWindowAttributes(hwnd, 0, RGB(40, 40, 40), LWA_ALPHA); // 去掉標(biāo)題欄及邊框 LONG_PTR Style = GetWindowLongPtr(hwnd, GWL_STYLE); Style = Style & ~WS_CAPTION & ~WS_SYSMENU & ~WS_SIZEBOX; SetWindowLongPtr(hwnd, GWL_STYLE, Style); // 至頂層窗口 最大化 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, iWidth, iHeight, SWP_SHOWWINDOW); // 設(shè)置窗體可穿透鼠標(biāo) SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT | WS_EX_LAYERED); // 繪圖 HDC hdc = ::GetDC(hwnd); HDC mdc = ::CreateCompatibleDC(hdc); // 創(chuàng)建畫(huà)筆 HPEN hpen = CreatePen(PS_SOLID, 10, RGB(0, 255, 0)); // DC 選擇畫(huà)筆 SelectObject(hdc, hpen); // (畫(huà)筆)從初始點(diǎn)移動(dòng)到 50,50 MoveToEx(hdc, 100, 100, NULL); // (畫(huà)筆)從初始點(diǎn)畫(huà)線到 100,100 LineTo(hdc, 1000, 1000); RECT rect = {0}; rect.bottom = 10; rect.left = 20; rect.right = 20; rect.top = 15; DrawText(hdc, L"hello lyshark.com", strlen("hello lyshark.com"), &rect, DT_CALCRECT | DT_CENTER | DT_SINGLELINE); } return 0; }
繪制效果圖:
接著我們使用Imgui繪制一個(gè)動(dòng)態(tài)菜單,首先下載imgui并打開(kāi)項(xiàng)目中的examples
目錄,找到example_win32_directx9
打開(kāi)后自己配置好dx9SDK
開(kāi)發(fā)工具包。
代碼直接調(diào)用,并附加到Counter-Strike Source
游戲窗體之上即可,這段代碼也很簡(jiǎn)單。
#include "imgui.h" #include "imgui_impl_dx9.h" #include "imgui_impl_win32.h" #include <d3d9.h> #include <tchar.h> #include <iostream> #pragma execution_character_set("utf-8") // 全局變量 // lyshark.com static HWND hwnd; static HWND GameHwnd; static RECT WindowRectangle; static int WindowWide, WindowHeight; static LPDIRECT3D9 g_pD3D = NULL; static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; static D3DPRESENT_PARAMETERS g_d3dpp = {}; // 單選框設(shè)置狀態(tài) bool show_another_window = false; // imgui 回調(diào)函數(shù) extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // By: LyShark bool CreateDeviceD3D(HWND hWnd) { if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) { return false; } ZeroMemory(&g_d3dpp, sizeof(g_d3dpp)); g_d3dpp.Windowed = TRUE; g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; g_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; g_d3dpp.EnableAutoDepthStencil = TRUE; g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16; g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; if (g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0) { return false; } return true; } void CleanupDeviceD3D() { if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } if (g_pD3D) { g_pD3D->Release(); g_pD3D = NULL; } } void ResetDevice() { ImGui_ImplDX9_InvalidateDeviceObjects(); HRESULT hr = g_pd3dDevice->Reset(&g_d3dpp); if (hr == D3DERR_INVALIDCALL) { IM_ASSERT(0); } ImGui_ImplDX9_CreateDeviceObjects(); } LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) { return true; } switch (msg) { case WM_SIZE: if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED) { g_d3dpp.BackBufferWidth = LOWORD(lParam); g_d3dpp.BackBufferHeight = HIWORD(lParam); ResetDevice(); } return 0; case WM_SYSCOMMAND: if ((wParam & 0xfff0) == SC_KEYMENU) { return 0; } break; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } // 繪制主方法 // www.cnblogs.com/lyshark void DrawImGUI() { // 啟動(dòng)IMGUI自繪 ImGui_ImplDX9_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); static float f = 0.0f; static int counter = 0; static char sz[256] = { 0 }; ImGui::Begin("LyShark 輔助GUI主菜單"); ImGui::Text("這是一段測(cè)試字符串"); ImGui::Checkbox("彈出子窗口", &show_another_window); ImGui::SliderFloat("浮點(diǎn)條", &f, 0.0f, 1.0f); ImGui::InputText("輸入內(nèi)容", sz, 256, 0, 0, 0); if (ImGui::Button("點(diǎn)我觸發(fā)")) counter++; ImGui::SameLine(); ImGui::Text("觸發(fā)次數(shù) = %d", counter); ImGui::Text("當(dāng)前FPS: %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::End(); if (show_another_window) { ImGui::Begin("我是子窗體", &show_another_window); ImGui::Text(" 您好,LyShark !"); if (ImGui::Button("關(guān)閉窗體")) show_another_window = false; ImGui::End(); } ImGui::EndFrame(); } // 自身窗口循環(huán)事件 void WindowMessageLoop() { bool done = false; while (!done) { // 每次都將窗體置頂并跟隨游戲窗體移動(dòng) GetWindowRect(GameHwnd, &WindowRectangle); WindowWide = (WindowRectangle.right) - (WindowRectangle.left); WindowHeight = (WindowRectangle.bottom) - (WindowRectangle.top); DWORD dwStyle = GetWindowLong(GameHwnd, GWL_STYLE); if (dwStyle & WS_BORDER) { WindowRectangle.top += 23; WindowHeight -= 23; } // 跟隨窗口移動(dòng) MoveWindow(hwnd, WindowRectangle.left + 8, WindowRectangle.top + 8, WindowWide - 11, WindowHeight - 11, true); // 開(kāi)始消息循環(huán) MSG msg; while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); if (msg.message == WM_QUIT) { done = true; } } if (done) { break; } // 開(kāi)始繪制 DrawImGUI(); g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1.0f, 0); if (g_pd3dDevice->BeginScene() >= 0) { ImGui::Render(); ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData()); g_pd3dDevice->EndScene(); } HRESULT result = g_pd3dDevice->Present(NULL, NULL, NULL, NULL); if (result == D3DERR_DEVICELOST && g_pd3dDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) { ResetDevice(); } } } int main(int argc, char *argv[]) { // 注冊(cè)窗體類(lèi) WNDCLASSEX wc; // 附加到指定窗體上 wc.cbClsExtra = NULL; wc.cbSize = sizeof(WNDCLASSEX); wc.cbWndExtra = NULL; wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0)); wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hIconSm = LoadIcon(0, IDI_APPLICATION); wc.hInstance = GetModuleHandle(NULL); wc.lpfnWndProc = (WNDPROC)WndProc; wc.lpszClassName = L" "; wc.lpszMenuName = L" "; wc.style = CS_VREDRAW | CS_HREDRAW; RegisterClassEx(&wc); // 得到窗口句柄 GameHwnd = FindWindowA(NULL, "Counter-Strike Source"); GetWindowRect(GameHwnd, &WindowRectangle); WindowWide = WindowRectangle.right - WindowRectangle.left; WindowHeight = WindowRectangle.bottom - WindowRectangle.top; // 創(chuàng)建窗體 hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TOOLWINDOW, L" ", L" ", WS_POPUP, 1, 1, WindowWide, WindowHeight, 0, 0, wc.hInstance, 0); // 顯示窗口 SetLayeredWindowAttributes(hwnd, 0, RGB(0, 0, 0), LWA_ALPHA); SetLayeredWindowAttributes(hwnd, 0, RGB(0, 0, 0), LWA_COLORKEY); ShowWindow(hwnd, SW_SHOW); // 初始化D3D if (!CreateDeviceD3D(hwnd)) { CleanupDeviceD3D(); UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; } // 更新窗體 UpdateWindow(hwnd); // 初始化ImGUI ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; io.Fonts->AddFontFromFileTTF("c:/windows/fonts/simhei.ttf", 13.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); ImGui::StyleColorsDark(); ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX9_Init(g_pd3dDevice); // 開(kāi)始執(zhí)行繪制循環(huán)事件 WindowMessageLoop(); ImGui_ImplDX9_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); CleanupDeviceD3D(); DestroyWindow(hwnd); UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; }
繪制效果如下:
另外,Imgui也支持繪制到整個(gè)屏幕上,也可以當(dāng)作全局GUI界面來(lái)使用。
#include "imgui.h" #include "imgui_impl_dx9.h" #include "imgui_impl_win32.h" #include <d3d9.h> #include <tchar.h> #include <iostream> #pragma execution_character_set("utf-8") // 全局變量 static HWND hwnd; static HWND GameHwnd; static RECT WindowRectangle; static int WindowWide, WindowHeight; static LPDIRECT3D9 g_pD3D = NULL; static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; static D3DPRESENT_PARAMETERS g_d3dpp = {}; // 單選框設(shè)置狀態(tài) bool show_another_window = false; // imgui 回調(diào)函數(shù) // By: LyShark extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); bool CreateDeviceD3D(HWND hWnd) { if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) { return false; } ZeroMemory(&g_d3dpp, sizeof(g_d3dpp)); g_d3dpp.Windowed = TRUE; g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; g_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; g_d3dpp.EnableAutoDepthStencil = TRUE; g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16; g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; if (g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0) { return false; } return true; } void CleanupDeviceD3D() { if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } if (g_pD3D) { g_pD3D->Release(); g_pD3D = NULL; } } // https://www.cnblogs.com/lyshark void ResetDevice() { ImGui_ImplDX9_InvalidateDeviceObjects(); HRESULT hr = g_pd3dDevice->Reset(&g_d3dpp); if (hr == D3DERR_INVALIDCALL) { IM_ASSERT(0); } ImGui_ImplDX9_CreateDeviceObjects(); } LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) { return true; } switch (msg) { case WM_SIZE: if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED) { g_d3dpp.BackBufferWidth = LOWORD(lParam); g_d3dpp.BackBufferHeight = HIWORD(lParam); ResetDevice(); } return 0; case WM_SYSCOMMAND: if ((wParam & 0xfff0) == SC_KEYMENU) { return 0; } break; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } // 繪制主方法 // lyshark.com void DrawImGUI() { // 啟動(dòng)IMGUI自繪 ImGui_ImplDX9_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); static float f = 0.0f; static int counter = 0; static char sz[256] = { 0 }; ImGui::Begin("LyShark 輔助GUI主菜單"); ImGui::Text("這是一段測(cè)試字符串"); ImGui::Checkbox("彈出子窗口", &show_another_window); ImGui::SliderFloat("浮點(diǎn)條", &f, 0.0f, 1.0f); ImGui::InputText("輸入內(nèi)容", sz, 256, 0, 0, 0); if (ImGui::Button("點(diǎn)我觸發(fā)")) counter++; ImGui::SameLine(); ImGui::Text("觸發(fā)次數(shù) = %d", counter); ImGui::Text("當(dāng)前FPS: %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::End(); if (show_another_window) { ImGui::Begin("我是子窗體", &show_another_window); ImGui::Text(" 您好,LyShark !"); if (ImGui::Button("關(guān)閉窗體")) show_another_window = false; ImGui::End(); } ImGui::EndFrame(); } // 自身窗口循環(huán)事件 void WindowMessageLoop() { bool done = false; while (!done) { // 每次都將窗體置頂并跟隨游戲窗體移動(dòng) GetWindowRect(GameHwnd, &WindowRectangle); WindowWide = (WindowRectangle.right) - (WindowRectangle.left); WindowHeight = (WindowRectangle.bottom) - (WindowRectangle.top); DWORD dwStyle = GetWindowLong(GameHwnd, GWL_STYLE); if (dwStyle & WS_BORDER) { WindowRectangle.top += 23; WindowHeight -= 23; } // 跟隨窗口移動(dòng) MoveWindow(hwnd, WindowRectangle.left + 8, WindowRectangle.top + 8, WindowWide - 11, WindowHeight - 11, true); // 開(kāi)始消息循環(huán) MSG msg; while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); if (msg.message == WM_QUIT) { done = true; } } if (done) { break; } // 開(kāi)始繪制 DrawImGUI(); g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1.0f, 0); if (g_pd3dDevice->BeginScene() >= 0) { ImGui::Render(); ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData()); g_pd3dDevice->EndScene(); } HRESULT result = g_pd3dDevice->Present(NULL, NULL, NULL, NULL); if (result == D3DERR_DEVICELOST && g_pd3dDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) { ResetDevice(); } } } int main(int argc, char *argv[]) { // 注冊(cè)窗體類(lèi) WNDCLASSEX wc; // 附加到整個(gè)屏幕上 wc.cbClsExtra = NULL; wc.cbSize = sizeof(WNDCLASSEX); wc.cbWndExtra = NULL; wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0)); wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hIconSm = LoadIcon(0, IDI_APPLICATION); wc.hInstance = GetModuleHandle(NULL); wc.lpfnWndProc = (WNDPROC)WndProc; wc.lpszClassName = L" "; wc.lpszMenuName = L" "; wc.style = CS_VREDRAW | CS_HREDRAW; ::RegisterClassEx(&wc); // 屏幕寬度和高度 WindowWide = GetSystemMetrics(SM_CXSCREEN); WindowHeight = GetSystemMetrics(SM_CYSCREEN); // 創(chuàng)建窗體 HWND hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TOOLWINDOW, L" ", L" ", WS_POPUP, 1, 1, WindowWide, WindowHeight, 0, 0, wc.hInstance, 0); // 顯示窗口 SetLayeredWindowAttributes(hwnd, 0, 1.0f, LWA_ALPHA); SetLayeredWindowAttributes(hwnd, 0, RGB(0, 0, 0), LWA_COLORKEY); ShowWindow(hwnd, SW_SHOW); // 初始化D3D if (!CreateDeviceD3D(hwnd)) { CleanupDeviceD3D(); UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; } // 更新窗體 UpdateWindow(hwnd); // 初始化ImGUI ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; io.Fonts->AddFontFromFileTTF("c:/windows/fonts/simhei.ttf", 13.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); ImGui::StyleColorsDark(); ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX9_Init(g_pd3dDevice); // 開(kāi)始執(zhí)行繪制循環(huán)事件 WindowMessageLoop(); ImGui_ImplDX9_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); CleanupDeviceD3D(); DestroyWindow(hwnd); UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; }
繪制效果如下:
以上就是C++利用ImGUI繪制D3D外部菜單的詳細(xì)內(nèi)容,更多關(guān)于C++ ImGUI繪制D3D外部菜單的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
QT Creator+OpenCV實(shí)現(xiàn)圖像灰度化的示例代碼
這篇文章主要為大家詳細(xì)介紹了QT如何利用Creator和OpenCV實(shí)現(xiàn)圖像灰度化效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-12-12簡(jiǎn)單比較C語(yǔ)言中的execl()函數(shù)與execlp()函數(shù)
這篇文章主要介紹了C語(yǔ)言中的execl()函數(shù)與execlp()函數(shù)的簡(jiǎn)單比較,是C語(yǔ)言入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-08-08在Qt中使用QtWebApp搭建HTTP服務(wù)器的詳細(xì)步驟
QtWebApp是一個(gè)開(kāi)源項(xiàng)目,它基于著名的Qt?Framework開(kāi)發(fā),提供了一種在C++環(huán)境中構(gòu)建HTTP服務(wù)器的解決方案,這篇文章主要給大家介紹了關(guān)于在Qt中使用QtWebApp搭建HTTP服務(wù)器的詳細(xì)步驟,需要的朋友可以參考下2024-07-07C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的掃雷游戲操作
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的掃雷游戲操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03C++中的std::format?如何實(shí)現(xiàn)編譯期格式檢查
C++?20?的?std::format?是一個(gè)很神奇、很實(shí)用的工具,最神奇的地方在于它能在編譯期檢查字符串的格式是否正確,而且不需要什么特殊的使用方法,只需要像使用普通函數(shù)那樣傳參即可,這篇文章主要介紹了std::format?如何實(shí)現(xiàn)編譯期格式檢查,需要的朋友可以參考下2024-04-04