Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

☑️ Checkbox Component - 复选框组件

状态:✅ 已完成
难度:⭐⭐
代码行数:~282 行


📋 组件概述

Checkbox 是一个交互式复选框组件,演示了双状态管理、点击交互和勾选标记(✓)的绘制技术。

核心功能

  • 双状态管理:选中(checked)/ 未选中(unchecked)
  • 点击切换:鼠标点击复选框切换状态
  • 勾选标记绘制:使用旋转矩形绘制 ✓ 符号
  • 悬停效果:鼠标悬停时的高亮反馈
  • 多复选框支持:同时管理多个独立复选框
  • 键盘控制:空格键切换第一个选项
  • 实时统计:显示选中数量

🎨 视觉效果

复选框状态

状态 描述 视觉效果
未选中 默认状态 空的方框
选中 激活状态 方框内显示绿色 ✓
悬停 鼠标悬停 高亮边框 + 半透明外框

组件布局

┌──────────────────────────────────┐
│  Checkbox Component Demo         │
│  [Space] Toggle first option     │
│  [ESC] Quit                      │
│                                  │
│  ☑ Enable Notifications          │
│  ☐ Auto-save                     │
│  ☐ Dark Mode                     │
│  ☑ Show Tips                     │
│                                  │
│  Checked: 2 / 4                  │
│                        ✓  ← 装饰性标记
└──────────────────────────────────┘

🖱️ 交互演示

鼠标交互

// 1. 获取鼠标位置
float mouseX, mouseY;
input->getMousePosition(mouseX, mouseY);

// 2. 检测点击
if (isMousePressed && !wasMousePressed) {
    // 检查是否点击在复选框内
    for (int i = 0; i < 4; i++) {
        if (isPointInCheckbox(mouseX, mouseY, checkboxes[i])) {
            // 切换状态
            *(checkboxes[i].checked) = !*(checkboxes[i].checked);
            break;
        }
    }
}

键盘控制

按键 功能
Space 切换第一个复选框
ESC 退出程序

🎯 核心实现

1. 复选框数据结构

struct CheckboxData {
    float x, y, size;        // 位置和大小
    bool* checked;           // 状态指针
    const char* label;       // 标签文本
};

// 复选框数组
CheckboxData checkboxes[4];

2. 点击检测

bool isPointInCheckbox(float x, float y, const CheckboxData& checkbox) const {
    return x >= checkbox.x && 
           x <= checkbox.x + checkbox.size &&
           y >= checkbox.y && 
           y <= checkbox.y + checkbox.size;
}

3. 勾选标记绘制

勾选标记由两条旋转的矩形线段组成:

void drawCheckmark(float centerX, float centerY, float size, const float* color) {
    // 短边(左下 → 中间)
    float x1 = centerX - size * 0.3f;
    float y1 = centerY;
    float x2 = centerX - size * 0.05f;
    float y2 = centerY + size * 0.25f;
    
    // 计算旋转角度
    float angle1 = std::atan2(y2 - y1, x2 - x1);
    
    // 绘制旋转矩形
    renderer->drawRectangle(...);
    
    // 长边(中间 → 右上)
    float x3 = centerX - size * 0.05f;
    float y3 = centerY + size * 0.25f;
    float x4 = centerX + size * 0.35f;
    float y4 = centerY - size * 0.3f;
    
    // 绘制第二段
    renderer->drawRectangle(...);
}

4. 复选框渲染

void drawCheckbox(const CheckboxData& checkbox, bool isHovered) {
    // 1. 绘制背景
    renderer->drawRectangle(checkbox.x, checkbox.y, 
                           checkbox.size, checkbox.size, 
                           colorBoxBg);
    
    // 2. 绘制边框(上下左右四条)
    float borderWidth = 2.0f;
    // ... 绘制四条边框
    
    // 3. 如果选中,绘制勾选标记
    if (*(checkbox.checked)) {
        drawCheckmark(...);
    }
    
    // 4. 绘制标签
    renderer->drawText(checkbox.label, ...);
    
    // 5. 如果悬停,绘制高亮
    if (isHovered) {
        float highlightColor[4] = {0.5f, 0.5f, 0.6f, 0.3f};
        renderer->drawRectangle(..., highlightColor);
    }
}

🔬 技术要点

1. 旋转矩形绘制

由于渲染 API 只提供 drawRectangle,要绘制勾选标记需要:

  • 计算线段的角度(atan2
  • 计算线段的长度(sqrt
  • 使用旋转后的矩形近似线段

2. 多复选框管理

bool option1 = true;
bool option2 = false;
bool option3 = false;
bool option4 = true;

// 使用指针数组管理
CheckboxData checkboxes[4] = {
    {x, y, size, &option1, "Enable Notifications"},
    {x, y, size, &option2, "Auto-save"},
    {x, y, size, &option3, "Dark Mode"},
    {x, y, size, &option4, "Show Tips"}
};

3. 悬停检测

// 每帧获取鼠标位置
float mouseX, mouseY;
input->getMousePosition(mouseX, mouseY);

// 渲染时检测悬停
for (int i = 0; i < 4; i++) {
    bool isHovered = isPointInCheckbox(mouseX, mouseY, checkboxes[i]);
    drawCheckbox(checkboxes[i], isHovered);
}

📊 性能分析

渲染调用统计

每帧渲染调用(4 个复选框):

  • 背景矩形:4 次
  • 边框矩形:16 次(每个复选框 4 条边)
  • 勾选标记:~6 次(每个选中的复选框 2-3 次调用)
  • 文本渲染:5 次(4 个标签 + 1 个统计信息)
  • 装饰性标记:3 次(可选)

总计:约 30-35 次渲染调用/帧


🎓 学习要点

初学者

  1. 双状态管理

    • 如何表示和切换 true/false 状态
    • 使用指针管理多个状态
  2. 点击检测

    • 点对矩形的碰撞检测
    • 鼠标按下/释放状态判断
  3. 基础图形绘制

    • 矩形边框的绘制技巧
    • 复合图形的组合

进阶开发者

  1. 向量图形绘制

    • 使用基础图元组合复杂形状
    • 旋转矩形实现任意角度线段
  2. 交互设计

    • 视觉反馈的重要性
    • 悬停状态的实现
  3. 数据结构设计

    • 使用结构体组织复选框数据
    • 指针在状态管理中的应用

🚀 扩展方向

简单扩展

  • 三态复选框:添加"部分选中"状态
  • 禁用状态:灰色显示且无法点击
  • 动画效果:勾选标记的出现/消失动画

中等扩展

  • 单选框(Radio):同一组内只能选中一个
  • 复选框组:管理相关复选框的组
  • 全选/反选:批量操作功能

高级扩展

  • 自定义勾选标记:支持不同样式的勾选符号
  • 键盘导航:Tab 键切换焦点,Enter 键确认
  • 数据绑定:与数据模型双向绑定

🏗️ 构建与运行

构建步骤

# 1. 配置项目
cd examples/cpp/checkbox
cmake -S . -B build -G "Visual Studio 17 2022" -A x64

# 2. 编译
cmake --build build --config Release

# 3. 复制 DLL 到运行时目录
copy build\Release\Release\checkbox.dll ..\..\..\..\native\build\Release\

# 4. 编译着色器
cd assets\shaders
compile_shaders.bat

运行组件

cd ..\..\..\..\native
.\build\Release\bitui_native.exe .\build\Release\checkbox.dll

📁 文件结构

checkbox/
├── checkbox.cpp                      # 组件实现(~282 行)
├── CMakeLists.txt                    # 构建配置
├── README.md                         # 本文档
├── assets/
│   └── shaders/                      # 着色器目录
│       ├── triangle.vert             # 顶点着色器(GLSL)
│       ├── triangle.frag             # 片段着色器(GLSL)
│       ├── compile_shaders.bat       # 着色器编译脚本
│       └── spv/                      # 编译后的 SPIR-V
│           ├── triangle_vert.spv
│           └── triangle_frag.spv
└── build/                            # 构建输出
    └── Release/
        └── Release/
            └── checkbox.dll          # 组件库

🔗 相关组件

组件 关系 说明
Button 兄弟组件 类似的点击交互模式
Switch 兄弟组件 同样是双状态组件
Radio 未实现 单选框(互斥选择)

📚 参考资料

API 使用

  • IInput::isMouseButtonPressed(int button) - 检测鼠标按键状态
  • IInput::getMousePosition(float& x, float& y) - 获取鼠标位置
  • IInput::isKeyJustPressed(int keyCode) - 检测键盘按键
  • IRenderer::drawRectangle() - 绘制矩形
  • IRenderer::drawText() - 绘制文本

数学函数

  • std::atan2(dy, dx) - 计算向量角度
  • std::sqrt(x) - 计算平方根
  • std::sin(x) - 正弦函数(用于动画)

💡 最佳实践

  1. 状态管理

    • 使用指针统一管理多个复选框的状态
    • 保持状态变量的独立性
  2. 交互反馈

    • 提供明确的视觉反馈(悬停、选中)
    • 支持多种输入方式(鼠标、键盘)
  3. 代码组织

    • 使用结构体封装复选框数据
    • 分离检测逻辑和绘制逻辑
  4. 图形绘制

    • 分层绘制(背景 → 边框 → 标记 → 标签)
    • 使用常量颜色便于修改

🐛 调试建议

常见问题

  1. 点击无响应

    • 检查鼠标坐标系统
    • 验证碰撞检测范围
    • 确认 wasMousePressed 状态正确更新
  2. 勾选标记显示异常

    • 检查旋转角度计算
    • 验证矩形的位置和大小
    • 确认颜色 alpha 通道不为 0
  3. 悬停效果不准确

    • 检查 isPointInCheckbox 的边界条件
    • 验证鼠标坐标是否正确获取

📈 版本历史

  • v1.0 (2025-10-12) - 初始版本
    • 实现基础复选框功能
    • 支持 4 个独立复选框
    • 添加悬停和点击交互
    • 实现勾选标记绘制

📞 技术支持

  • 项目主页:Bit HCI
  • 文档:docs/guides/
  • 示例:examples/cpp/

Happy Coding! 🎉