FLTK 控件简介

FLTK 控件简介

📚 写在前面

FLTK(Fast Light Toolkit)是一个轻量级的跨平台 C++ GUI 库,以其小巧、快速和易用著称。与 Qt 或 wxWidgets 相比,FLTK 的整个库大小只有几 MB,非常适合嵌入式系统、工具软件开发以及需要快速原型设计的场景。

本文将从基础到进阶,全面介绍 FLTK 的核心控件体系,帮助你在实际项目中灵活运用。


🎯 控件继承体系概览

FLTK 采用经典的面向对象设计,所有控件都继承自 Fl_Widget 基类:

Fl_Widget (抽象基类)
├── Fl_Box # 静态盒子(标签、分隔线)
├── Fl_Button # 按钮基类
│ ├── Fl_Button # 普通按钮
│ ├── Fl_Toggle_Button # 开关按钮
│ ├── Fl_Check_Button # 复选框
│ └── Fl_Radio_Button # 单选按钮
├── Fl_Input_ # 输入控件基类
│ ├── Fl_Input # 单行输入框
│ ├── Fl_Int_Input # 整数输入框
│ ├── Fl_Float_Input # 浮点数输入框
│ └── Fl_Text_Editor # 多行文本编辑器
├── Fl_Valuator # 数值调节控件基类
│ ├── Fl_Slider # 滑块
│ ├── Fl_Scrollbar # 滚动条
│ ├── Fl_Dial # 旋钮
│ └── Fl_Counter # 计数器
├── Fl_Group # 容器基类
│ ├── Fl_Window # 窗口
│ ├── Fl_Scroll # 滚动区域
│ ├── Fl_Tabs # 标签页
│ ├── Fl_Pack # 自动布局容器
│ └── Fl_Table # 表格控件
├── Fl_Browser # 文件/列表浏览器
├── Fl_Menu_Bar # 菜单栏
├── Fl_Tree # 树形控件
├── Fl_Progress # 进度条
└── Fl_Help_View # HTML帮助视图

🎨 基础显示控件

1. Fl_Box —— 最简洁的静态控件

Fl_Box 是 FLTK 中最简单的控件,仅用于显示文本或图形,不响应用户交互。

核心特性:

  • 纯展示性控件,不可点击
  • 支持各种边框样式
  • 可作为布局占位符或分隔线

常用方法:

Fl_Box* box = new Fl_Box(x, y, w, h, "label");
box->box(FL_UP_BOX);           // 设置边框样式
box->labelsize(16);            // 字体大小
box->labelfont(FL_BOLD);       // 字体样式
box->labelcolor(FL_RED);       // 文字颜色
box->align(FL_ALIGN_CENTER);   // 对齐方式

边框样式枚举:

  • FL_NO_BOX – 无边框
  • FL_FLAT_BOX – 扁平边框
  • FL_UP_BOX – 凸起效果
  • FL_DOWN_BOX – 凹陷效果
  • FL_ROUNDED_BOX – 圆角边框
  • FL_SHADOW_BOX – 阴影效果

代码示例:

// 创建各种样式的盒子
Fl_Box* title = new Fl_Box(50, 10, 200, 30, "应用程序标题");
title->box(FL_FLAT_BOX);
title->labelsize(20);
title->labelfont(FL_BOLD);

Fl_Box* separator = new Fl_Box(50, 50, 300, 5, "");
separator->box(FL_THIN_DOWN_BOX);

Fl_Box* content = new Fl_Box(50, 70, 300, 100, "这里是内容区域");
content->box(FL_ENGRAVED_BOX);
content->align(FL_ALIGN_INSIDE | FL_ALIGN_TOP_LEFT);

🔘 按钮控件家族

2. Fl_Button —— 标准按钮

最基本的交互控件,用户点击时触发回调函数。

核心特性:

  • 支持按下/释放状态
  • 可设置快捷键
  • 支持工具提示

常用方法:

Fl_Button* btn = new Fl_Button(x, y, w, h, "按钮文字");
btn->callback(my_callback, data);  // 设置回调
btn->shortcut(FL_CTRL + 's');      // 快捷键 Ctrl+S
btn->tooltip("这是提示文本");       // 鼠标悬停提示
btn->setonly();                    // 设置为默认按钮(回车触发)
btn->value(1);                     // 设置按下状态

代码示例:

// 回调函数
void on_click(Fl_Widget* w, void* data) {
    Fl_Button* btn = (Fl_Button*)w;
    fl_message("按钮被点击了!当前标签:%s", btn->label());
}

// 创建按钮
Fl_Button* btn1 = new Fl_Button(50, 50, 100, 30, "点我");
btn1->callback(on_click);

Fl_Button* btn2 = new Fl_Button(50, 100, 100, 30, "退出");
btn2->callback([](Fl_Widget*, void* data) {
    ((Fl_Window*)data)->hide();  // 使用 lambda 关闭窗口
}, window);

3. Fl_Toggle_Button —— 开关按钮

按压后保持状态,再次按压才弹起。

代码示例:

Fl_Toggle_Button* toggle = new Fl_Toggle_Button(50, 50, 100, 30, "开关");
toggle->callback([](Fl_Widget* w, void*) {
    Fl_Toggle_Button* btn = (Fl_Toggle_Button*)w;
    if (btn->value()) {
        fl_message("开关已打开");
    } else {
        fl_message("开关已关闭");
    }
});

4. Fl_Check_Button —— 复选框

多选场景,通常多个复选框组合使用。

代码示例:

Fl_Check_Button* opt1 = new Fl_Check_Button(50, 50, 120, 25, "选项一");
Fl_Check_Button* opt2 = new Fl_Check_Button(50, 80, 120, 25, "选项二");
Fl_Check_Button* opt3 = new Fl_Check_Button(50, 110, 120, 25, "选项三");

// 获取选中状态
bool isChecked = opt1->value();

5. Fl_Radio_Button —— 单选按钮

互斥选择,同一组的单选按钮只有一个能被选中。

代码示例:

// 方法1:使用 Fl_Group 管理分组
Fl_Group* group = new Fl_Group(50, 50, 150, 100);
group->begin();

Fl_Radio_Button* radio1 = new Fl_Radio_Button(50, 50, 100, 25, "选项 A");
Fl_Radio_Button* radio2 = new Fl_Radio_Button(50, 80, 100, 25, "选项 B");
Fl_Radio_Button* radio3 = new Fl_Radio_Button(50, 110, 100, 25, "选项 C");

group->end();

// 方法2:使用 Fl_Radio_Round_Button 获得圆形外观
Fl_Radio_Round_Button* radio_r1 = new Fl_Radio_Round_Button(200, 50, 100, 25, "圆形选项");

📝 文本输入控件

6. Fl_Input —— 单行文本输入

常用方法:

Fl_Input* input = new Fl_Input(x, y, w, h, "标签");
input->value("默认文本");           // 设置/获取文本
input->maximum_size(100);          // 最大字符数
input->readonly(1);                // 只读模式
input->password(1);                // 密码模式(显示星号)
input->wrap(1);                    // 自动换行

代码示例:

// 用户名输入框
Fl_Input* username = new Fl_Input(120, 50, 150, 25, "用户名:");

// 密码输入框
Fl_Input* password = new Fl_Input(120, 90, 150, 25, "密码:");
password->password(1);

// 只读显示框
Fl_Input* display = new Fl_Input(120, 130, 150, 25, "结果:");
display->readonly(1);

7. Fl_Int_Input & Fl_Float_Input —— 数字输入

自动校验输入内容,只能输入数字。

代码示例:

Fl_Int_Input* age = new Fl_Int_Input(120, 50, 100, 25, "年龄:");
age->value("18");

Fl_Float_Input* price = new Fl_Float_Input(120, 90, 100, 25, "价格:");
price->value("99.99");

8. Fl_Text_Editor —— 多行文本编辑器

功能丰富的文本编辑控件,支持选择、复制、粘贴等操作。

代码示例:

// 创建文本编辑器
Fl_Text_Editor* editor = new Fl_Text_Editor(50, 50, 400, 300);
Fl_Text_Buffer* buffer = new Fl_Text_Buffer();  // 文本缓冲区
editor->buffer(buffer);                          // 绑定缓冲区

// 设置初始文本
buffer->text("这是多行文本编辑器\n支持换行\n可以编辑大量内容");

// 设置编辑器样式
editor->textfont(FL_COURIER);    // 等宽字体
editor->textsize(12);            // 字体大小
editor->wrap_mode(Fl_Text_Editor::WRAP_AT_BOUNDS, 0);  // 自动换行

🎚️ 数值调节控件

9. Fl_Slider —— 滑块

用于在范围内选择数值,支持水平和垂直方向。

常用方法:

Fl_Slider* slider = new Fl_Slider(x, y, w, h, "标签");
slider->bounds(0, 100);          // 设置取值范围
slider->value(50);               // 设置当前值
slider->step(1);                 // 设置步长
slider->slider_size(0.1);        // 滑块大小比例

滑块类型枚举:

  • FL_VERTICAL – 垂直滑块
  • FL_HORIZONTAL – 水平滑块
  • FL_VERT_FILL_SLIDER – 填充式垂直滑块
  • FL_HOR_FILL_SLIDER – 填充式水平滑块
  • FL_VERT_NICE_SLIDER – 精美样式垂直滑块
  • FL_HOR_NICE_SLIDER – 精美样式水平滑块

代码示例:

// 水平滑块
Fl_Slider* h_slider = new Fl_Slider(50, 50, 200, 20, "音量");
h_slider->type(FL_HORIZONTAL);
h_slider->bounds(0, 100);
h_slider->value(50);

// 带数值显示的滑块
Fl_Value_Slider* v_slider = new Fl_Value_Slider(50, 100, 200, 25, "亮度");
v_slider->bounds(0, 100);
v_slider->callback([](Fl_Widget* w, void*) {
    Fl_Value_Slider* s = (Fl_Value_Slider*)w;
    printf("当前值: %.1f\n", s->value());
});

10. Fl_Dial —— 旋钮控件

圆形旋钮,通过旋转来调节数值。

代码示例:

Fl_Dial* dial = new Fl_Dial(50, 50, 80, 80, "音量");
dial->bounds(0, 100);
dial->value(50);
dial->step(1);

11. Fl_Counter —— 计数器

带有加减按钮的数值调节控件。

代码示例:

Fl_Counter* counter = new Fl_Counter(50, 50, 120, 25, "数量:");
counter->bounds(1, 99);
counter->value(1);
counter->step(1);
counter->lstep(10);  // 点击按钮时的步进值
counter->callback([](Fl_Widget* w, void*) {
    Fl_Counter* c = (Fl_Counter*)w;
    fl_message("当前数量: %d", (int)c->value());
});

12. Fl_Scrollbar —— 滚动条

用于滚动区域的控制器,通常与 Fl_Scroll 配合使用。


📦 容器控件

13. Fl_Window —— 顶层窗口

所有 FLTK 程序的根容器,代表一个操作系统窗口。

代码示例:

// 标准窗口
Fl_Window* win = new Fl_Window(800, 600, "我的应用程序");

// 无边框窗口
Fl_Window* frameless = new Fl_Window(800, 600, "无边框窗口");
frameless->border(0);  // 移除边框

// 模态对话框
Fl_Window* dialog = new Fl_Window(300, 200, "提示");
dialog->set_modal();   // 设置为模态

14. Fl_Group —— 基础容器

用于将多个控件组合在一起,支持批量操作和布局管理。

代码示例:

Fl_Group* group = new Fl_Group(50, 50, 300, 150, "控制面板");
group->box(FL_ENGRAVED_BOX);
group->begin();

// 添加控件到组内
Fl_Button* btn1 = new Fl_Button(60, 70, 80, 30, "按钮1");
Fl_Button* btn2 = new Fl_Button(150, 70, 80, 30, "按钮2");
Fl_Button* btn3 = new Fl_Button(240, 70, 80, 30, "按钮3");

group->end();

// 批量操作
group->deactivate();   // 禁用组内所有控件
group->activate();     // 启用组内所有控件

15. Fl_Scroll —— 滚动区域

当内容超出可视区域时自动显示滚动条。

代码示例:

Fl_Scroll* scroll = new Fl_Scroll(50, 50, 400, 300);
scroll->type(Fl_Scroll::BOTH);  // 水平和垂直滚动
scroll->begin();

// 添加大量内容
for (int i = 0; i < 20; i++) {
    char label[32];
    snprintf(label, sizeof(label), "项目 %d", i + 1);
    new Fl_Button(10, i * 35, 100, 25, label);
}
new Fl_Box(10, 800, 100, 25, "底部内容");

scroll->end();

16. Fl_Tabs —— 标签页容器

管理多个页面,通过点击标签切换。

代码示例:

Fl_Tabs* tabs = new Fl_Tabs(50, 50, 400, 300);

// 第一个标签页
Fl_Group* tab1 = new Fl_Group(50, 80, 400, 270, "基本设置");
tab1->begin();
Fl_Button* btn1 = new Fl_Button(60, 100, 100, 30, "按钮1");
Fl_Input* input1 = new Fl_Input(60, 150, 200, 25, "输入框:");
tab1->end();

// 第二个标签页
Fl_Group* tab2 = new Fl_Group(50, 80, 400, 270, "高级设置");
tab2->begin();
Fl_Check_Button* check1 = new Fl_Check_Button(60, 100, 120, 25, "启用高级功能");
Fl_Slider* slider1 = new Fl_Slider(60, 150, 200, 20, "阀值:");
tab2->end();

tabs->end();

17. Fl_Pack —— 自动布局容器

自动排列子控件,支持水平和垂直方向。

代码示例:

// 垂直布局
Fl_Pack* vpack = new Fl_Pack(50, 50, 200, 200);
vpack->type(Fl_Pack::VERTICAL);
vpack->spacing(10);  // 间距

vpack->begin();
for (int i = 0; i < 5; i++) {
    char label[32];
    snprintf(label, sizeof(label), "按钮 %d", i + 1);
    new Fl_Button(0, 0, 180, 30, label);
}
vpack->end();

// 水平布局
Fl_Pack* hpack = new Fl_Pack(280, 50, 300, 50);
hpack->type(Fl_Pack::HORIZONTAL);
hpack->begin();
new Fl_Button(0, 0, 80, 30, "确定");
new Fl_Button(0, 0, 80, 30, "取消");
new Fl_Button(0, 0, 80, 30, "应用");
hpack->end();

18. Fl_Table —— 表格控件

功能强大的表格控件,支持自定义绘制。你之前的 CDDTS Agent 程序已经用到了这个控件。


🌲 其他实用控件

19. Fl_Browser —— 文件/列表浏览器

用于显示文件列表或选项列表。

代码示例:

Fl_Browser* browser = new Fl_Browser(50, 50, 200, 300);
browser->type(FL_HOLD_BROWSER);  // 单选模式

// 添加项目
browser->add("项目 1");
browser->add("项目 2");
browser->add("项目 3");

// 设置回调
browser->callback([](Fl_Widget* w, void*) {
    Fl_Browser* b = (Fl_Browser*)w;
    int index = b->value();  // 获取选中项索引
    const char* text = b->text(index);  // 获取选中项文本
    fl_message("选中: %s", text);
});

// 文件浏览器模式
browser->type(FL_MULTI_BROWSER);   // 多选模式
browser->type(FL_SELECT_BROWSER);  // 单选模式
browser->type(FL_HOLD_BROWSER);    // 保持高亮模式

20. Fl_Menu_Bar —— 菜单栏

创建应用程序的标准菜单栏。

代码示例:

Fl_Menu_Bar* menubar = new Fl_Menu_Bar(0, 0, 800, 25);

// 添加菜单项
menubar->add("文件/新建", FL_CTRL + 'n', menu_callback, (void*)"new");
menubar->add("文件/打开", FL_CTRL + 'o', menu_callback, (void*)"open");
menubar->add("文件/保存", FL_CTRL + 's', menu_callback, (void*)"save");
menubar->add("文件/分隔线");
menubar->add("文件/退出", FL_CTRL + 'q', [](Fl_Widget*, void*) {
    exit(0);
});

menubar->add("编辑/复制", FL_CTRL + 'c', menu_callback);
menubar->add("编辑/粘贴", FL_CTRL + 'v', menu_callback);

menubar->add("帮助/关于", 0, about_callback);

21. Fl_Progress —— 进度条

显示任务完成进度。

代码示例:

Fl_Progress* progress = new Fl_Progress(50, 50, 300, 25);
progress->bounds(0, 100);
progress->value(0);
progress->color(FL_GREEN);
progress->selection_color(FL_DARK_GREEN);

// 模拟进度更新
void update_progress(Fl_Progress* p, int target) {
    for (int i = 0; i <= target; i++) {
        p->value(i);
        Fl::check();  // 更新界面
        Fl::wait(0.05);  // 延迟
    }
}

22. Fl_Tree —— 树形控件

用于展示层次结构数据。

代码示例:

Fl_Tree* tree = new Fl_Tree(50, 50, 200, 300);
tree->showroot(1);  // 显示根节点

// 添加节点
Fl_Tree_Item* root = tree->root();
Fl_Tree_Item* item1 = tree->add("根节点/子项1");
Fl_Tree_Item* item2 = tree->add("根节点/子项2");
Fl_Tree_Item* sub1 = tree->add("根节点/子项1/孙项1");

// 设置回调
tree->callback([](Fl_Widget* w, void*) {
    Fl_Tree* t = (Fl_Tree*)w;
    Fl_Tree_Item* item = t->callback_item();
    if (item) {
        fl_message("选中: %s", item->label());
    }
});

23. Fl_Help_View —— HTML 帮助视图

显示富文本内容(支持简单的 HTML)。

代码示例:

Fl_Help_View* help = new Fl_Help_View(50, 50, 400, 300);
help->load("help.html");  // 从文件加载
// 或直接设置 HTML 内容
help->value("<h1>帮助文档</h1><p>这是<b>FLTK</b>应用程序的帮助内容</p>");

24. Fl_Chart —— 图表控件

简单图表绘制控件。

代码示例:

Fl_Chart* chart = new Fl_Chart(50, 50, 300, 200);
chart->type(FL_BAR_CHART);  // 条形图
// chart->type(FL_LINE_CHART);  // 折线图
// chart->type(FL_FILL_CHART);  // 填充图
// chart->type(FL_SPIKE_CHART); // 脉冲图

chart->add(30, "Jan");
chart->add(45, "Feb");
chart->add(58, "Mar");
chart->add(42, "Apr");
chart->add(67, "May");

chart->maxnum(10);  // 最大数据点数
chart->bounds(0, 100);  // 取值范围

🎯 控件通用属性

所有 FLTK 控件都继承自 Fl_Widget,因此都具备以下通用属性和方法:

位置和大小

widget->resize(x, y, w, h);  // 改变位置和大小
widget->x(); widget->y();     // 获取位置
widget->w(); widget->h();     // 获取大小

标签和文字

cpp

widget->label("新标签");       // 设置标签
widget->copy_label("副本");    // 复制标签(深拷贝)
widget->labelcolor(FL_RED);   // 标签颜色
widget->labelsize(14);        // 标签字体大小
widget->labelfont(FL_BOLD);   // 标签字体样式
widget->align(FL_ALIGN_CENTER); // 对齐方式

颜色和样式

widget->color(FL_BLUE);           // 背景色
widget->selection_color(FL_RED);  // 选中/激活时的颜色
widget->labelcolor(FL_WHITE);     // 文字颜色
widget->box(FL_UP_BOX);           // 边框样式

状态管理

widget->show();           // 显示
widget->hide();           // 隐藏
widget->activate();       // 启用
widget->deactivate();     // 禁用
widget->visible();        // 是否可见
widget->active();         // 是否可用

事件回调

widget->callback(my_callback, user_data);  // 设置回调函数
widget->do_callback();                     // 触发回调
widget->when(FL_WHEN_CHANGED);             // 设置触发时机

when() 的可选值:

  • FL_WHEN_NEVER – 从不触发
  • FL_WHEN_CHANGED – 值改变时触发
  • FL_WHEN_RELEASE – 鼠标释放时触发
  • FL_WHEN_ENTER_KEY – 按下回车键时触发

💡 实用技巧和最佳实践

1. 使用智能指针管理控件

#include <memory>
std::unique_ptr<Fl_Window> window(new Fl_Window(800, 600, "App"));

2. 批量设置控件样式

void set_widget_style(Fl_Widget* w, int size, Fl_Font font, Fl_Color color) {
    w->labelsize(size);
    w->labelfont(font);
    w->labelcolor(color);
}

3. 动态创建和删除控件

// 动态添加
Fl_Button* btn = new Fl_Button(10, next_y, 100, 30, label);
next_y += 40;
parent->add(btn);
parent->redraw();

// 动态删除
delete btn;
parent->redraw();

4. 布局管理辅助函数

void center_widget(Fl_Widget* w, int container_w, int container_h) {
    w->position((container_w - w->w()) / 2, (container_h - w->h()) / 2);
}

📖 学习资源推荐

官方资源

书籍推荐

  • FLTK Programming Manual (官方手册,PDF 免费)
  • Introduction to FLTK (初学者友好)

示例代码

FLTK 安装目录下的 examples/ 文件夹包含了丰富的示例程序:

  • button.cxx – 各种按钮示例
  • input.cxx – 输入控件示例
  • table.cxx – 表格控件示例
  • browser.cxx – 浏览器控件示例

🚀 总结

FLTK 提供了一套完整且易用的 GUI 控件体系,通过本文的详细介绍,你应该已经对各个控件有了全面的认识。

学习路线建议:

  1. Fl_WindowFl_Button 开始,掌握基本的事件处理
  2. 学习 Fl_GroupFl_Pack,理解布局管理
  3. 深入研究 Fl_TableFl_Tree 等复杂控件
  4. 阅读官方示例代码,实践各种控件的组合使用

FLTK 的学习曲线相对平缓,非常适合快速开发小型工具和跨平台应用。希望这篇博客能帮助你在 FLTK 开发之路上走得更顺利!

如果你有任何问题或想要深入了解某个特定控件,欢迎随时交流讨论!

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注