# 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

# HiEasyX
[](https://opensource.org/licenses/MIT)
[](https://en.cppreference.com/w/cpp/20)
[](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 功能强大,可以构建非常复杂的界面。以下是一些示例:


### 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