EUI-NEO声明式DSL实战:像搭积木一样写C++界面,10分钟掌握核心写法
【免费下载链接】EUI-NEOEUI-NEO is a cross-platform, high-performance, low-overhead C++17 GPUI framework项目地址: https://gitcode.com/gh_mirrors/eui3/EUI-NEO
EUI-NEO 是一个跨平台、高性能的 C++17 GUI 框架,它的声明式 DSL(Domain-Specific Language)让你只需描述"界面长什么样",布局、状态、事件、动画和渲染全部由内部 Runtime 自动完成。这篇 EUI-NEO DSL 教程面向新手,带你用积木式的链式 API,10 分钟写出第一个 C++ 桌面界面。
先睹为快——下面这些精美界面,全部由这套声明式 DSL 搭成:
为什么 EUI-NEO 的 DSL 对新手友好?
传统 C++ 写界面,往往要手动创建窗口、管理控件生命周期、逐行处理坐标。EUI-NEO 的思路反过来:你只声明结构 + 样式 + 状态,Runtime 负责剩下的一切(见 docs/DSL.md):
- 按 id 缓存元素实例,每帧自动回收;
- 统一处理点击、悬停、拖拽等命中测试;
- 自动推进过渡动画、维护脏区重绘,省电又流畅;
- 颜色支持
#RRGGBB字符串,写起来和 Web CSS 一样直观。
官方 Gallery 应用(apps/gallery/app.cpp)里,白天/黑夜主题一键切换,全部靠声明式写法驱动:
三步创建第一个 EUI-NEO 窗口应用
第 1 步:准备工程。需要 CMake 3.14+ 和一个 C++17 编译器,把 EUI-NEO 放到3rd/EUI-NEO(克隆失败可用镜像git clone https://gitcode.com/gh_mirrors/eui3/EUI-NEO 3rd/EUI-NEO)。CMake 里只需三行关键配置:
add_subdirectory(3rd/EUI-NEO) add_executable(my_app main.cpp) eui_neo_configure_app(my_app)第 2 步:只实现两个函数。这是 DSL 应用的全部骨架——配置对象dslAppConfig()描述窗口属性,compose()描述页面内容(完整入口封装在 include/eui/dsl_app.h):
#include "eui_neo.h" namespace app { const DslAppConfig& dslAppConfig() { static const DslAppConfig config = DslAppConfig{} .title("My App") .pageId("my_app") .windowSize(960, 640); return config; } void compose(eui::Ui& ui, const eui::Screen& screen) { ui.column("root") .size(screen.width, screen.height) .padding(32.0f) .content([&] { ui.text("title") .text("Hello EUI-NEO") .fontSize(28.0f) .build(); }) .build(); } } // namespace app第 3 步:编译运行。
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --config Release --paralleleui_neo_configure_app()会自动选择 GLFW/SDL2 入口、链接eui::neo并部署运行时资源,你不需要直接引用core/下的任何文件。更多安装细节见 docs/集成指南.md。
像搭积木一样:9 种核心元素与容器
DSL 只有一小组核心元素(docs/DSL.md),学会它们就能搭出任何界面:
| 元素 | 作用 | 典型场景 |
|---|---|---|
ui.row(id) | 横向布局容器 | 工具栏、卡片行 |
ui.column(id) | 纵向布局容器 | 页面主干 |
ui.stack(id) | 叠放容器 | 背景 + 内容分层 |
ui.flow(id) | 流式容器,自动换行 | 标签云、图片墙 |
ui.rect(id) | 矩形图元 | 面板、按钮背景 |
ui.text(id) | 文本图元 | 标题、正文 |
ui.image(id) | 图片图元 | 本地/网络图片、SVG |
ui.polygon(id) | 多边形图元 | 扇形、tooltip 指针 |
ui.shadertoy(id) | GPU 着色图元 | 炫技背景 |
每个元素都是链式调用 +build()收尾的积木。以仓库里的 Clock 时钟应用为例(apps/clock/app.cpp),页面根节点就是一块ui.stack积木,背景是一块ui.rect,其余内容层层叠加:
常用布局属性几乎和 Web CSS 同构,看一眼就会:
ui.rect("card") .size(360.0f, 260.0f) // 宽高 .color("#1E293B") // 颜色直接写 HEX 字符串 .radius(18.0f) // 圆角 .border(1.0f, "#38BDF880") // 边框(支持带透明度的 8 位 HEX) .shadow(26.0f, 0.0f, 8.0f, {0, 0, 0, 0.26f}) .build();.margin(...)、.gap(...)、.justifyContent(...)、.fill()(填充父容器)、.wrapContent()(自适应内容)等属性都支持,容器嵌套组合即可表达复杂版面。
10 行代码加上点击事件与过渡动画
交互是声明式的:任意元素都支持.onClick(...)等回调,Runtime 自动完成命中测试与按下捕获。给时钟应用加一个"城市卡片",点击即切换——本质只是改一个状态变量,下一帧compose()重新描述目标状态,动画由.transition(...)+.animate(...)声明驱动:
ui.rect("city.card") .size(300.0f, 96.0f) .radius(14.0f) .color(selected ? "#111827" : "#F9FAFB") .transition(0.2f, eui::Ease::OutCubic) // 200ms 过渡 .animate(eui::AnimProperty::Frame | eui::AnimProperty::Opacity) .onClick([] { state.selectedCity = cityIndex; }) .build();同样的模式让 Gallery 应用实现了白天/黑夜双主题:状态一变,整页颜色、图表、控件全部平滑过渡(见 apps/gallery/pages/gallery_style.h):
可动画属性覆盖 Rect 的颜色/圆角/阴影/变换、Text 的字号颜色、Image 的 tint/圆角等,完整列表见 docs/动画.md。
直接用组件层:按钮、图表、日期选择器开箱即用
不想从零拼装图元?components/下有一整套现成组件(components/components.h),它们本身就是 DSL 图元的组合:
components::button(ui, "save") .size(180.0f, 54.0f) .icon(0xF0C7) .text("Save") .colors("#2563EB", "#3B82F6", "#1D4ED8") // 正常/悬停/按下三色 .transition(0.18f) .onClick([] { /* 修改状态即可 */ }) .build();组件清单相当齐全:button、checkbox、slider、input、tabs、dropdown、datePicker、colorPicker、dialog、toast、lineChart/barChart/pieChart图表三件套,还有面向长列表的virtualList和scrollView。文章开头那张 Controls 面板里的按钮、输入框、复选框、图表,正是这些组件的集中展示。
从时钟到画廊:一个 DSL 撑起完整应用
官方仓库里的apps/是最好的进阶教材:apps/clock/ 是单页工具类应用,而 apps/calgary_gallery/ 则展示了多页面导航、页内动画和图片布局。它的页面按 apps/calgary_gallery/pages/ 拆分,每个页面就是一个compose片段;图片图元用.cover()自适应裁剪、.radius()加圆角,直接把画作变成精致的画廊卡片:
这个画廊应用还内置了 Bing 每日图片源(.bingDaily(0, "zh-CN"))、主题色采样等能力,说明 DSL 图元与平台能力(网络、字体、图片)是无缝打通的。
常见写法避坑清单
新手最容易踩的几个点(依据 docs/DSL.md 的"当前限制"一节):
- 布局容器没有 Frame 动画。
Row/Column/Stack/Flow的尺寸变化会立即重排,不会平滑插值;需要"展开"动效时,保持容器逻辑尺寸稳定,让内部Rect等叶子节点去动画。可运行参考:examples/animated_card.cpp。 - zIndex 只影响绘制层级,不影响布局。装饰背景层请用
.ignoreLayout(),而不是z(-1)。 - 颜色优先写 HEX 字符串。
#RGB/#RGBA/#RRGGBB/#RRGGBBAA都支持,比浮点 RGBA 直观得多;外部输入建议用eui::Color::tryFromHex校验。 - 超长列表用
virtualList。只 compose 可见行,避免一次性构建百万节点卡死界面。
下一步:继续深入的官方资料
掌握本文的"配置 + compose 双函数"骨架和积木式图元写法后,推荐按这个顺序读文档:
- docs/DSL.md:DSL 设计与当前实现的完整说明;
- docs/布局.md 与 docs/事件.md:布局属性和交互回调细节;
- docs/组件.md:组件层全量 API;
- examples/ 下的
eui_demo.cpp、shadertoy.cpp等单屏演示,以及 apps/ 下的多页完整应用源码。
从"Hello EUI-NEO"到画廊应用,EUI-NEO 的声明式 DSL 证明了 C++ 写界面也可以像搭积木一样清晰。现在动手,把第一个compose()跑起来吧 🚀
【免费下载链接】EUI-NEOEUI-NEO is a cross-platform, high-performance, low-overhead C++17 GPUI framework项目地址: https://gitcode.com/gh_mirrors/eui3/EUI-NEO
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考