状态:✅ 已完成
难度:⭐⭐
代码行数:~420 行
Tooltip(提示框)组件是一个悬停提示组件,当鼠标悬停在特定区域时显示提示信息。支持淡入淡出动画、智能定位、延迟显示等功能,是提升用户体验的重要组件。
- ✅ 鼠标悬停检测:实时检测鼠标位置
- ✅ 延迟显示:防止误触发(0.5秒延迟)
- ✅ 淡入淡出动画:平滑的透明度过渡
- ✅ 智能定位:跟随鼠标或固定位置
- ✅ 边界检测:自动调整位置防止超出屏幕
- ✅ 圆角背景:美观的提示框样式
- ✅ 进度指示:显示悬停延迟进度
┌──────────────────┐
│ ┌──────────────┐ │
│ │ 按钮区域 │ │ ← 悬停触发区域(高亮)
│ └──────────────┘ │
│ ═════════ │ ← 悬停进度条
│ │
│ ╭─────────────╮│
│ │ TOOLTIP TEXT││ ← 淡入的提示框(圆角)
│ ╰─────────────╯│
└──────────────────┘
- 跟随鼠标:提示框跟随鼠标移动(带偏移)
- 固定位置:相对于触发区域固定显示(上/下/左/右)
struct Tooltip {
// 触发区域
float triggerX, triggerY; // 位置
float triggerW, triggerH; // 尺寸
// 提示文本
const char* text;
// 样式
float bgColor[4]; // 背景颜色
float textColor[4]; // 文字颜色
float textSize; // 字体大小
// 状态
bool isHovering; // 是否悬停
float hoverTime; // 悬停时长
float alpha; // 当前透明度
// 定位
bool followMouse; // 是否跟随鼠标
float offsetX, offsetY; // 偏移量
};// 鼠标位置转换(屏幕坐标 → 渲染坐标)
mouseX = screenX - windowWidth / 2;
mouseY = screenY - windowHeight / 2;
// 矩形碰撞检测
bool isMouseInRect(float x, float y, float w, float h) {
return mouseX >= x && mouseX <= x + w &&
mouseY >= y && mouseY <= y + h;
}// 更新悬停时间
if (isHovering) {
hoverTime += deltaTime;
} else {
hoverTime = 0.0f;
}
// 延迟阈值
const float HOVER_DELAY = 0.5f;
// 目标透明度
float targetAlpha = (hoverTime >= HOVER_DELAY) ? 1.0f : 0.0f;const float FADE_SPEED = 4.0f; // 淡入淡出速度
// 平滑过渡
if (alpha < targetAlpha) {
alpha += FADE_SPEED * deltaTime;
if (alpha > targetAlpha) alpha = targetAlpha;
} else if (alpha > targetAlpha) {
alpha -= FADE_SPEED * deltaTime;
if (alpha < targetAlpha) alpha = targetAlpha;
}
// 应用到颜色
float finalColor[4] = {
color[0], color[1], color[2],
color[3] * alpha // 透明度调制
};// 跟随鼠标模式
if (followMouse) {
tooltipX = mouseX + offsetX;
tooltipY = mouseY + offsetY;
}
// 固定位置模式
else {
float centerX = triggerX + triggerW / 2;
float centerY = triggerY + triggerH / 2;
tooltipX = centerX + offsetX - tooltipW / 2;
tooltipY = centerY + offsetY - tooltipH / 2;
}
// 边界限制(防止超出屏幕)
if (tooltipX + tooltipW > screenRight)
tooltipX = screenRight - tooltipW;
if (tooltipX < screenLeft)
tooltipX = screenLeft;
if (tooltipY + tooltipH > screenBottom)
tooltipY = screenBottom - tooltipH;
if (tooltipY < screenTop)
tooltipY = screenTop;const float cornerRadius = 4.0f;
// 主体矩形(水平和垂直)
drawRectangle(x + cornerRadius, y, w - cornerRadius * 2, h, color);
drawRectangle(x, y + cornerRadius, w, h - cornerRadius * 2, color);
// 四个圆角
drawCircle(x + cornerRadius, y + cornerRadius, cornerRadius, color);
drawCircle(x + w - cornerRadius, y + cornerRadius, cornerRadius, color);
drawCircle(x + cornerRadius, y + h - cornerRadius, cornerRadius, color);
drawCircle(x + w - cornerRadius, y + h - cornerRadius, cornerRadius, color);// 创建跟随鼠标的 tooltip
Tooltip tooltip1 = {
// 触发区域
-200.0f, -100.0f, 120.0f, 40.0f,
// 提示文本
"HOVER ME",
// 样式
{0.2f, 0.3f, 0.5f, 0.95f}, // 蓝色半透明背景
{1.0f, 1.0f, 1.0f, 1.0f}, // 白色文字
12.0f, // 字体大小
// 状态(初始化为 false/0.0)
false, 0.0f, 0.0f,
// 跟随鼠标,偏移 (15, 15)
true, 15.0f, 15.0f
};
// 创建固定位置的 tooltip(上方)
Tooltip tooltip2 = {
-50.0f, -100.0f, 120.0f, 40.0f,
"TOOLTIP ABOVE",
{0.3f, 0.5f, 0.3f, 0.95f},
{1.0f, 1.0f, 1.0f, 1.0f},
12.0f,
false, 0.0f, 0.0f,
// 固定位置,向上偏移 50px
false, 0.0f, -50.0f
};void onUpdate(float deltaTime) {
// 获取鼠标位置
float mx, my;
input->getMousePosition(mx, my);
// 更新每个 tooltip
for (auto& tooltip : tooltips) {
updateTooltip(tooltip, deltaTime);
}
}
void onRender() {
// 1. 绘制触发区域
for (const auto& tooltip : tooltips) {
drawTriggerArea(tooltip);
}
// 2. 绘制 tooltips(alpha > 0 的才绘制)
for (const auto& tooltip : tooltips) {
if (tooltip.alpha > 0.01f) {
drawTooltip(tooltip);
}
}
}| 按键 | 功能 |
|---|---|
| 鼠标悬停 | 触发提示框显示 |
| Space | 暂停/继续动画 |
| R | 重置所有状态 |
| ESC | 退出程序 |
- 顶部左侧:运行时间和鼠标坐标
- 顶部右侧:暂停状态指示
- 底部:操作提示
- 触发区域:高亮显示和进度条
- 防止快速移动鼠标时误触发
- 0.5秒延迟,可自定义
- 视觉进度条反馈
- 淡入淡出效果
- 基于时间的插值
- 流畅的视觉体验
- 两种定位模式
- 自动边界检测
- 防止超出屏幕
- 圆角背景
- 半透明效果
- 自定义颜色
- 只渲染可见的 tooltip
- 高效的碰撞检测
- 优化的绘制调用
// 获取鼠标位置
input->getMousePosition(x, y);
// 坐标系转换
renderX = screenX - screenWidth / 2;
renderY = screenY - screenHeight / 2;
// 碰撞检测
bool isInside = (x >= left && x <= right &&
y >= top && y <= bottom);// 状态:未悬停 → 延迟中 → 显示中 → 淡出
if (isHovering) {
hoverTime += deltaTime;
if (hoverTime >= DELAY) {
// 显示状态
}
} else {
hoverTime = 0;
// 淡出状态
}// 线性插值(Lerp)
current = current + (target - current) * speed * deltaTime;
// 限制范围
if (current > target) current = target;
if (current < target) current = target;// Alpha 混合
finalColor.rgb = color.rgb;
finalColor.a = color.a * animationAlpha;- 箭头指示器:添加指向触发区域的箭头
- 多行文本:支持换行显示
- 自定义动画:缩放、滑入等效果
- 丰富内容:支持图标、按钮等
- HTML 样式:支持富文本格式
- 触发方式:点击、长按等
- 主题系统:预设样式模板
- 性能优化:空间分区、视锥剔除
| 指标 | 数值 |
|---|---|
| Tooltip 数量 | 6 个 |
| 绘制调用 | ~30 次/帧 |
| FPS | ~240 |
| 内存占用 | <150 KB |
| CPU 使用 | <3% |
| 延迟响应 | 0.5秒 |
| 动画速度 | 4.0x/秒 |
- ✅ 鼠标坐标需要转换为渲染坐标系
- ✅ 延迟时间影响用户体验,建议 0.3-0.8 秒
- ✅ 淡入淡出速度需要平衡流畅性和响应性
- ✅ 边界检测要考虑提示框实际尺寸
- ✅ 文本宽度估算可能不准确,建议预留空间
- ✅ 圆角效果用圆形拼接,可能有细微视觉问题
tooltip/
├── tooltip.cpp # 主要实现(~420 行)
├── CMakeLists.txt # 构建配置
├── assets/
│ └── shaders/
│ ├── triangle.vert # 顶点着色器(共享)
│ ├── triangle.frag # 片段着色器(共享)
│ └── spv/
│ ├── triangle_vert.spv
│ └── triangle_frag.spv
└── README.md # 本文档
cd examples/cpp/tooltip
mkdir build && cd build
cmake .. -G "Visual Studio 17 2022" -A x64
cmake --build . --config Releasecd native
.\build\Release\bitui_native.exe .\build\Release\tooltip.dll- ✅ 悬停在各个区域,观察 tooltip 显示
- ✅ 快速移动鼠标,验证延迟机制
- ✅ 检查淡入淡出动画是否平滑
- ✅ 测试边界检测(移动到屏幕边缘)
- ✅ 观察跟随鼠标和固定位置的区别
- ✅ 验证进度条显示正确
- 按钮说明
- 图标解释
- 功能介绍
- 快捷键提示
- 图表数值
- 统计信息
- 详细描述
- 帮助文档
- 操作提示
- 状态说明
- 错误信息
- 警告提醒
- Label:静态文本显示(Tooltip 的基础)
- Button:可添加 Tooltip 的按钮
- Modal:更复杂的弹出层
- Dropdown:下拉菜单(类似机制)
| API | 说明 | 状态 |
|---|---|---|
drawText() |
文本渲染 | ✅ 已实现 |
drawRectangle() |
矩形背景 | ✅ 已实现 |
drawCircle() |
圆角效果 | ✅ 已实现 |
getMousePosition() |
鼠标位置 | ✅ 已实现 |
IInput |
输入检测 | ✅ 已实现 |
IWindow |
窗口控制 | ✅ 已实现 |
维护者:Bit Project 团队
最后更新:2025-10-12
版本:v1.0.0