# HiEasyX **Repository Path**: gfigure/hi-easyx ## Basic Information - **Project Name**: HiEasyX - **Description**: HiEasyX 是为 EasyX 图形库设计的轻量级扩展库,旨在帮助开发者快速构建 GUI 测试界面或开发简单图形应用程序。通过即时模式(IMGUI)设计,HiEasyX 提供简洁高效的 GUI 元素管理,同时集成实用绘图辅助功能,大幅降低 EasyX 用户的上手门槛和开发成本。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 26 - **Forks**: 3 - **Created**: 2025-02-09 - **Last Updated**: 2026-05-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: GUI, UI, EasyX, imgui ## README
![](readme/logo.svg) # HiEasyX [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![C++20](https://img.shields.io/badge/C%2B%2B-20-blue.svg)](https://en.cppreference.com/w/cpp/20) [![Platform](https://img.shields.io/badge/platform-Windows-lightgrey.svg)](https://www.microsoft.com/windows) [官网](https://www.hieasyx.cn) Windows 下的即时模式 GUI 库,基于 EasyX 构建,使用 D2D 绘图加速、抗锯齿。
--- ## Table of Contents - [Overview](#overview) - [Concept](#concept) - [Features](#features) - [Quick Start](#quick-start) - [Examples](#examples) - [Best Practices](#best-practices) - [Building](#building) - [License](#license) --- ## Overview HiEasyX 是一个面向 Windows 的 IMGUI(Immediate Mode GUI)库,基于 EasyX 构建。它不在操作系统层面创建窗口句柄,而是直接在 EasyX 的 `IMAGE` 缓冲区上绘制控件。这意味着你可以把它当作一层绘图代码,叠加在现有的 EasyX 程序上——不需要修改任何已有的 `circle`、`line`、`putimage` 调用。 从最初的教学辅助工具演化到现在,HiEasyX 已经是一套包含 40 余个模块、30 多个独立示例的 GUI 基础设施,支持三套完整的视觉主题、五区域 DockSpace 布局、蓝图节点编辑器、代码编辑器、动画系统等。它不再是测试版本,目前已在多个课程作业和毕业设计中被实际采用。 HiEasyX 功能强大,可以构建非常复杂的界面。以下是一些示例: ![](./readme/ide.png) ![](./readme/blueprint.png) ### Who Is This For **如果你正在用 EasyX 写带界面的程序:** - 不需要手写消息循环和 GDI 绘制,也不需要引入重量级 UI 框架 - 几行代码就能搭出按钮、滑块、文本输入框 - 接入成本接近于零:保留所有现有的 EasyX 绘图调用,只需在帧循环里插入几行 HiEasyX 代码 **如果你需要快速搭建工具界面或原型:** - IMGUI 的代码即界面方式适合快速迭代,没有设计器文件和资源文件的管理负担 - DockSpace、Viewport、Splitter 等布局系统可以组合出接近商业 IDE 的复杂界面 - 蓝图节点编辑器和代码编辑器提供了可视化脚本和文本编辑的能力 **如果你是图形学教学或算法可视化场景:** - 动画系统内置 26 种缓动曲线,适合演示过渡效果 - 控件状态由库托管,学生可以把注意力放在算法逻辑而非界面框架上 - 主题系统一键切换,演示时可以根据投影环境选择高对比或低对比方案 ### Requirements - Windows 10/11 - Visual Studio 2022(或兼容的 MSVC STL + Clang) - CMake 3.29 及以上 - EasyX 2023-07-23 或更新版本 - C++20 --- ## Concept ### The Problem 在 EasyX 里做 GUI,通常面临两种选择,都不怎么理想: ```cpp // 方案一:手写 GDI + 消息循环 // 每个按钮要自己画矩形、检测鼠标、处理点击、管理状态 // 100 行代码搭不出 5 个控件 // 方案二:引入一套传统 UI 框架 // 需要设计器、资源文件、事件回调、窗口句柄 // 项目变得臃肿,和 EasyX 的渲染管线也很难协同 ``` 第一种方案在控件数量上去之后完全不可维护;第二种方案对于一个小型工具或课程作业来说太重了,而且往往会接管消息循环,和 EasyX 的 `getmessage`/`peekmessage` 产生冲突。 ### The Approach HiEasyX 采用 IMGUI 范式:界面的描述和逻辑写在同一段代码里,每帧重新构建,控件状态由库内部托管。 ```cpp #include #include int main() { initgraph(640, 480); BeginBatchDraw(); HX::HXInitForEasyX(); HX::ApplyModernTheme(); HX::SetBuffer(GetWorkingImage()); HX::WindowProfile wp; wp.Size = {400, 250}; while (true) { cleardevice(); HX::HXBegin(); ExMessage msg{}; while (peekmessage(&msg)) HX::PushMessage(HX::GetHXMessage(&msg)); HX::Window(HXStr("Hello"), wp); HX::Text(HXStr("Hello HiEasyX!")); static int count = 0; static HX::ButtonProfile bp; if (HX::Button(HXStr("Click me"), bp)) ++count; static float val = 0; static HX::SliderProfile1f sp{0.f, 1.f}; HX::Slider1f(HXStr("Slider"), val, sp); HX::End(); HX::Render(); FlushBatchDraw(); } } ``` 这段代码里没有窗口句柄、没有事件回调、没有设计器文件。`Button` 的返回值直接告诉你这帧有没有被点中,`Slider1f` 直接修改你传入的引用。如果你熟悉 Dear ImGui,这套 API 不会让你感到陌生。 ### Implementation **渲染后端。** 默认使用 Direct2D + DirectWrite,动态加载 `d2d1.dll` 和 `dwrite.dll`,不强制静态链接。D2D 提供字体抗锯齿和亚像素定位,在高 DPI 屏幕上比 GDI 清晰。如果目标机器不支持 D2D(比如某些精简版 Windows),自动回退到 EasyX 的 GDI 绘制,无需改动代码。 **状态管理。** IMGUI 的经典难题是状态存在哪里。HiEasyX 使用 `HXStatePool`——一个以 `std::wstring` 为键的全局状态池。每个控件在第一次出现时自动在池中创建条目,后续帧通过相同的 ID 取回状态。这意味着你的界面代码可以写成几乎纯函数的形式,不需要在文件顶部维护一堆静态变量来保存控件的内部状态。 **绘制批处理。** 每个窗口的绘制命令先记录到一个 `HXDrawList` 中,帧末按裁剪矩形排序后一次性提交。这避免了传统 IMGUI 中频繁的 `SetWorkingImage` 切换。对于 Viewport、DockSlot、Scroller 等子区域,库内部使用对象池管理的 SubPainter,在帧间复用缓冲区,避免每帧的堆分配。 **主题系统。** `HXTheme` 结构体包含 50 余个设计 token(颜色、字号、圆角、间距)。`ApplyModernTheme()` 会一次性设置所有 token,支持 ModernDark、ModernDim、ModernLight 三套预设。需要自定义时直接修改全局 `Theme` 变量即可。 --- ## Features ### 基础控件 基础控件的 API 风格保持一致:通过 `Profile` 结构体传入样式和状态,函数返回值表示交互事件。 ```cpp HX::Window(HXStr("Main"), wp); HX::Text(HXStr("Label")); static HX::ButtonProfile bp; if (HX::Button(HXStr("OK"), bp)) { // 这帧被点击了 } static bool checked = false; static HX::CheckboxProfile cp; HX::Checkbox(HXStr("Enable"), cp); checked = cp.Checked; static float value = 0.5f; static HX::SliderProfile1f sp{0.f, 100.f}; HX::Slider1f(HXStr("Value"), value, sp); static HX::TextInputProfile tp{HXStr("placeholder"), {300, 40}}; HX::TextInput(tp); // tp.Text 即为当前输入内容 ``` ### 布局系统 ```cpp // DockSpace:五区域分割 + MDI 标签页 HX::DockSpaceProfile dsp{}; dsp.AvailableRect = HXRect{0, 0, 1600, 900}; dsp.LeftRatio = 0.2f; dsp.RightRatio = 0.25f; dsp.BottomRatio = 0.2f; HX::BeginDockSpace(HXStr("ide"), dsp); if (HX::BeginDockSlot(HXStr("ide"), HX::HXDockSlot::Left, HXStr("Explorer"))) { HX::TreeView(HXStr("tree"), nodes, tvp); HX::EndDockSlot(); } if (HX::BeginDockSlot(HXStr("ide"), HX::HXDockSlot::Center, HXStr("Editor"))) { HX::TextEditor(HXStr("editor"), lines, ep); HX::EndDockSlot(); } if (HX::BeginDockSlot(HXStr("ide"), HX::HXDockSlot::Right, HXStr("Inspector"))) { HX::PropertyGrid(HXStr("props"), items, pg); HX::EndDockSlot(); } HX::EndDockSpace(HXStr("ide"), dsp); ``` DockSpace 自动处理分割条拖拽、比例记忆、标签页切换。同一个 slot 支持多个 PanelId,自动渲染 TabBar 切换。 Viewport 用于在窗口内部创建独立的离屏渲染区域: ```cpp HX::ViewportProfile vp{}; vp.Size = {400, 300}; if (HX::BeginViewport(vp)) { // 这里面的控件渲染到离屏缓冲区 HX::Button(HXStr("Inside Viewport"), bp); HX::EndViewport(vp); } // 自动将子缓冲区贴回父窗口 ``` ### 蓝图节点编辑器 一个完整的可视化节点图系统,支持数据流和控制流: ```cpp static HX::HXNodeGraph graph; static HX::BlueprintProfile bp; bp.Graph = &graph; if (HX::BeginBlueprint(HXStr("bp1"), bp)) { // 由库根据 graph.Nodes / graph.Links 渲染画布 HX::EndBlueprint(); } ``` 画布支持缩放/平移、Bezier 连线、节点拖拽、框选、复制粘贴、右键上下文菜单、连线删除(从 pin 拖出或右键点击连线)。执行引擎支持 Branch、Sequence、ForLoop、变量表,以及自定义节点注册。 ### 代码编辑器 基于行虚拟化的文本编辑区,只渲染可见行: ```cpp std::vector lines = { HXStr("int main() {"), HXStr(" return 0;"), HXStr("}") }; HX::TextEditorProfile ep; HX::TextEditor(HXStr("editor"), lines, ep); ``` 内置 C++ 词法高亮(80+ 关键字、预处理器、字符字面量、多进制数字),支持光标导航、选择、IME 输入。通过 `profile.Lexer` 可替换为自定义词法器。 ### 动画与交互 ```cpp static HX::HXAnimationFloat anim; anim.Start = 0.0f; anim.End = 100.0f; anim.DurationMs = 800.0f; anim.Ease = HX::HXEaseType::EaseOutBack; float value = HX::Animate(anim, deltaMs); ``` 支持 `HXAnimationFloat`、`HXAnimationPoint`、`HXAnimationColor`、`HXAnimationRect`,共 26 种缓动曲线。配合模态对话框、弹出菜单、拖拽放置、全局快捷键,可以构建出完整的交互流程。 ### 主题 ```cpp HX::ApplyModernTheme(HX::HXThemeMode::ModernDark); // 或 ModernDim、ModernLight // 自定义单个 token HX::Theme.AccentPrimary = HXColor{255, 100, 50, 255}; ``` --- ## Quick Start ### Installation 将源码加入你的项目: 1. 克隆仓库 2. 将项目根目录加入头文件搜索路径(`include_directories(./)`) 3. 将 `source/` 和 `include/` 下的所有 `.cpp` / `.h` 文件加入编译 4. 确保编译定义包含 `UNICODE` 和 `_UNICODE` 或使用 CMake: ```cmake add_subdirectory(HiEasyX) target_link_libraries(your_target HiEasyXLib) ``` ### First Program ```cpp #include #include #include int main() { initgraph(800, 600); BeginBatchDraw(); HX::HXInitForEasyX(); HX::ApplyModernTheme(); HX::SetBuffer(HX::GetHXBuffer(GetWorkingImage())); while (true) { cleardevice(); HX::HXBegin(); ExMessage msg{}; while (peekmessage(&msg)) HX::PushMessage(HX::GetHXMessage(&msg)); HX::WindowProfile wp; HX::Window(HXStr("Hello"), wp); HX::Text(HXStr("Hello HiEasyX!")); static HX::ButtonProfile bp; if (HX::Button(HXStr("Click me"), bp)) { // handle click } HX::End(); HX::Render(); FlushBatchDraw(); } } ``` 完整代码见 `example/EasyX/HelloWorld.cpp`。 --- ## Examples `example/EasyX/` 目录下包含 30 余个独立示例,每个都是一个完整的 `main()` 函数: | 示例 | 内容 | |:-----|:-----| | HelloWorld | 最简集成:窗口、按钮、滑块、文本输入 | | Button / Checkbox / Slider / Dropdown / Tab / Menu / Tooltip | 各基础控件的独立演示 | | Panel / Group / Scroller / Horizontal / Containers | 容器与布局系统 | | DockSpace | 五区域分割面板 + MDI 标签页 | | Viewport | 离屏子缓冲区嵌套控件 | | Animation | 缓动动画与颜色插值 | | ModalDialog / PopupMenu | 模态对话框与右键菜单 | | BlueprintDemo / BlueprintFullDemo | 蓝图画布交互与执行引擎 | | TextInput | 文本输入与 IME 演示 | | ComprehensiveDemo | 多系统集成:动画、弹窗、模态、DockSpace | | ModernIDEPrototype / ModernEnginePrototype | IDE 与引擎编辑器界面原型 | | AutoTest | 自动化冒烟测试 | 建议从 `HelloWorld.cpp` 和 `ComprehensiveDemo.cpp` 开始,前者展示最基本的集成方式,后者展示多个子系统如何协同工作。 --- ## Best Practices ### Profile 必须使用 static IMGUI 每帧重建界面,控件状态通过 `Profile` 结构体持久化。如果 `Profile` 不是 `static`,每帧都会丢失状态(比如滑块位置、文本框内容、复选框选中状态)。 ```cpp // 正确:static 保证状态跨帧保留 static HX::SliderProfile1f sp{0.f, 100.f}; static float value = 50.f; HX::Slider1f(HXStr("Value"), value, sp); // 错误:每帧重新构造,状态无法保留 HX::SliderProfile1f sp{0.f, 100.f}; // DON'T DO THIS ``` ### ID 必须使用稳定字符串 HiEasyX 通过字符串 ID 在 `HXStatePool` 中存取状态。如果 ID 每帧变化(比如使用循环索引或动态拼接),会创建大量孤立状态条目,且某些功能(如 TextEditor 的双击选中、TabBar 的激活标签记忆)永远无法生效。 ```cpp // 正确:使用字面量或稳定的标识符 HX::TextEditor(HXStr("my_editor"), lines, ep); HX::TreeView(HXStr("asset_tree"), nodes, tvp); // 错误:ID 每帧变化 for (int i = 0; i < n; ++i) { HX::Button(HXStr("btn_") + std::to_wstring(i), bp); // DON'T DO THIS } ``` ### 帧循环三阶段 每帧必须按顺序调用 `HXBegin` → 控件代码 → `End` → `Render`: ```cpp HX::HXBegin(); // 重置帧状态 while (peekmessage(&msg)) // 将 EasyX 消息转给 HiEasyX HX::PushMessage(HX::GetHXMessage(&msg)); HX::Window(HXStr("Title"), wp); // 控件代码 // ... more controls ... HX::End(); // 处理 Tab 导航等收尾 HX::Render(); // 合成所有窗口到屏幕 ``` `HXBegin` 必须在所有消息处理和控件代码之前;`Render` 必须在 `FlushBatchDraw` 之前。 ### Theme 在初始化后设置 `ApplyModernTheme()` 必须在 `HXInitForEasyX()` 之后调用,否则部分后端状态尚未就绪: ```cpp HX::HXInitForEasyX(); HX::ApplyModernTheme(); // 正确 HX::SetBuffer(GetWorkingImage()); ``` ### 与 EasyX 混用 HiEasyX 不替换 EasyX 的绘图调用。你可以在同一个 `initgraph` 窗口中混用 EasyX 原生 API: ```cpp cleardevice(); HX::HXBegin(); // ... HiEasyX controls ... HX::End(); // EasyX 原生绘图 setlinecolor(RED); line(100, 100, 700, 500); HX::Render(); FlushBatchDraw(); ``` `example/EasyX/Dashboard.cpp` 展示了这种混用方式。 --- ## Building ### Dependencies | 依赖 | 必需 | 说明 | |:-----|:-----|:-----| | Windows 10/11 | 是 | 目标平台 | | Visual Studio 2022 | 是 | 或兼容的 MSVC STL + Clang | | CMake 3.29+ | 是 | 构建系统 | | EasyX 2023-07-23+ | 是 | 图形库 | | C++20 | 是 | 语言标准 | ### Build Commands 在 VS Developer Command Prompt 中执行: ```powershell git clone https://github.com/FSMargoo/HiEasyX.git cd HiEasyX mkdir cmake-build-debug && cd cmake-build-debug cmake .. -G Ninja -DCMAKE_CXX_COMPILER=clang++ ninja ``` 生成 Visual Studio 解决方案: ```powershell cmake .. -G "Visual Studio 17 2022" ``` 运行测试: ```powershell ctest ``` ### CMake Targets | Target | 说明 | |:-------|:-----| | `HiEasyXLib` | 静态库 | | `example_*` | 30+ 独立示例可执行文件 | --- ## License HiEasyX 以 MIT 协议开源。你可以在任何场合以任何目的免费使用,包括商业项目。 QQ 交流群:761990769