绘制一行文本

使用windows函数获取窗口句柄后使用imgui绘制。

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include "raylib.h"
#include "imgui.h"
#include "imgui_impl_win32.h"
#include "imgui_impl_opengl3.h"
#include "Win32Utils.h" // 引入隔离后的句柄获取函数

#ifndef _DEBUG
//#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 设置入口地址
#pragma comment(lib, "raylib.lib")
#pragma comment(lib, "winmm.lib")
// #pragma comment(lib, "opengl32.lib")
// #pragma comment(lib, "gdi32.lib")
// #pragma comment(lib, "shell32.lib")
// #pragma comment(lib, "user32.lib")
#endif // DEBIG
//-----------------------------------------------------------------------------------------------------


int main() {
// 1. 正常初始化 Raylib
InitWindow(1280, 720, "Fixed Conflict Architecture");

// 2. 通过隔离层安全获取 HWND
// 注意:ImGui_ImplWin32_Init 需要的是 HWND,它是 void* 的别名
void* handle = GetRaylibNativeWindow();

// 3. 初始化官方后端
ImGui::CreateContext();
ImGui_ImplWin32_Init(handle);
ImGui_ImplOpenGL3_Init("#version 330");

while (!WindowShouldClose()) {
// --- 逻辑与渲染 ---
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();

ImGui::Begin("Success!");
ImGui::Text("No Header Conflicts Anymore.");
ImGui::End();

BeginDrawing();
ClearBackground(BLACK);

ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
EndDrawing();
}

// 清理步骤...
return 0;
}

Win32Utils.h

1
2
3
#pragma once
// 这里不包含 raylib.h
void* GetRaylibNativeWindow();

Win32Utils.cpp

1
2
3
4
5
6
7
8
9
10
11
#define SM_CMONITORS 80 // 解决某些 Windows 宏缺失
#include <windows.h>
#define RAYLIB_H // 欺骗编译器,防止在此文件中包含 raylib.h 产生冲突
#include "Win32Utils.h"

// 引用外部函数声明,不需要包含整个 raylib.h
extern "C" void* GetWindowHandle(void);

void* GetRaylibNativeWindow() {
return GetWindowHandle();
}

配置编译环境

1.下载imgui

2.将相关文件链接到项目中

  1. 在vs2022中添加imgui目录与backend目录。

  2. 将所需cpp文件在项目中引用

    1
    2
    3
    4
    5
    imgui.cpp
    imgui_demo.cpp
    imgui_draw.cpp
    imgui_tables.cpp
    imgui_widgets.cpp
  3. 此项目需要引用win32+opengl3

    1
    2
    imgui_impl_opengl3.cpp
    imgui_impl_win32.cpp

绘制按钮并添加鼠标点击事件

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include "raylib.h"
#include "imgui.h"
#include "imgui_impl_win32.h"
#include "imgui_impl_opengl3.h"
#include "Win32Utils.h" // 引入隔离后的句柄获取函数

#pragma comment(lib, "opengl32.lib")

#ifndef _DEBUG
//#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 设置入口地址
#pragma comment(lib, "raylib.lib")
#pragma comment(lib, "winmm.lib")

// #pragma comment(lib, "gdi32.lib")
// #pragma comment(lib, "shell32.lib")
//#pragma comment(lib, "user32.lib")
#endif // DEBIG
//-----------------------------------------------------------------------------------------------------


#include "GuiManager.h"

// 专门存放 UI 布局的函数,让逻辑与框架分离---
void DrawMyUserInterface()
{
ImGui::Begin("control");
//ImGui::Text("state: running");
//static char buf[128] = "input this context";
//ImGui::InputText("srearch", buf, 128);

if (ImGui::Button("exec scan")) {
//具体的业务逻辑---
TraceLog(LOG_INFO, "start scan...");
}
ImGui::End();

}

int main() {
// 1. 初始化
GuiManager::Init(1280, 720, "Raylib + ImGui Pro");

// 2. 主循环
while (!WindowShouldClose()) {

// --- A. UI 准备 ---
GuiManager::NewFrame();

// --- B. UI 逻辑 (已封装) ---
DrawMyUserInterface();

// --- C. Raylib 场景逻辑 ---
// 只有当鼠标没在 UI 上时,才允许操作 3D 场景或游戏物体
if (GuiManager::ShouldProcessGameInput()) {
// 这里放你的 Raylib 绘图逻辑,比如 DrawCircle, DrawCube 等
BeginDrawing();
ClearBackground(DARKGRAY);
DrawText("Raylib 画出的字", 10, 50, 20, RAYWHITE);
// 注意:不要在 BeginDrawing 之后立刻 EndDrawing,
// 我们的 GuiManager::EndFrame 会处理 EndDrawing。
}

// --- D. 提交渲染 ---
GuiManager::EndFrame();
}

// 3. 资源释放
GuiManager::Shutdown();

return 0;
}

GuiManager.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once
#include "raylib.h"
#include "imgui.h"

namespace GuiManager {
// 启动环境
void Init(int width, int height, const char* title);

// 每一帧的开始和结束
void NewFrame();
void EndFrame();

// 销毁环境
void Shutdown();

// 辅助工具:判断当前是否该处理游戏逻辑
bool ShouldProcessGameInput();
}

Win32Utils.h

1
2
3
4
5
6
#pragma once

// 用 void* 替代 HWND,用 bool 替代逻辑
// 这样包含这个头文件的其他文件就不会被污染
void* GetNativeWindowHandle();
void InstallImGuiHook(void* windowHandle);

GuiManager.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include "GuiManager.h"
#include "raylib.h"
#include "Win32Utils.h" // 只包含我们的隔离接口
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include "imgui_impl_win32.h"

namespace GuiManager {


void GuiManager::Init(int w, int h, const char* title) {
InitWindow(w, h, title);

// 1. 获取句柄
void* handle = GetNativeWindowHandle();

// 2. 初始化 ImGui 基础
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
// --- 加载中文字体 ---
// 使用 Windows 自带的微软雅黑
const char* fontPath = "C:\\Windows\\Fonts\\msyh.ttc";
ImFont* font = io.Fonts->AddFontFromFileTTF(fontPath, 18.0f, NULL, io.Fonts->GetGlyphRangesChineseFull());
if (font == NULL) {
// 如果微软雅黑加载失败,尝试默认字体(虽然没中文但保证不崩溃)
io.Fonts->AddFontDefault();
}
// 3. 安装钩子(在隔离层里完成的,这里不涉及 windows.h)
InstallImGuiHook(handle);

// 4. 初始化后端
ImGui_ImplWin32_Init(handle);
ImGui_ImplOpenGL3_Init("#version 330");
}

void GuiManager::NewFrame() {
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();

BeginDrawing();
ClearBackground(DARKGRAY); // <--- 必须在这里!确保每一帧背景都是干净的
}

void EndFrame() {
// 1. 先把 ImGui 的逻辑转为顶点数据
ImGui::Render();

// 2. 此时已经在 BeginDrawing 中了,直接画 ImGui
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

// 3. 最后交换缓冲区
EndDrawing();
}

bool ShouldProcessGameInput() {
return !ImGui::GetIO().WantCaptureMouse && !ImGui::GetIO().WantCaptureKeyboard;
}

void Shutdown() {
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
CloseWindow();
}
}

Win32Utils.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "Win32Utils.h"
#include "imgui.h" // 必须包含,因为需要 LRESULT 和 HWND 的定义环境
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// 声明 Raylib 的内部函数(不需要包含 raylib.h)
extern "C" void* GetWindowHandle(void);

static WNDPROC OriginalRaylibProc = NULL;

// 我们的钩子函数
LRESULT CALLBACK MyInternalWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (ImGui_ImplWin32_WndProcHandler(hwnd, msg, wParam, lParam))
return 1;

// 此时 CallWindowProc 在 windows.h 的保护下绝对能找到
return CallWindowProc(OriginalRaylibProc, hwnd, msg, wParam, lParam);
}

void* GetNativeWindowHandle() {
return GetWindowHandle();
}

void InstallImGuiHook(void* windowHandle) {
HWND hwnd = (HWND)windowHandle;
if (hwnd && OriginalRaylibProc == NULL) {
OriginalRaylibProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)MyInternalWndProc);
}
}