FLTK-Rs

article/2025/9/1 13:29:34

终于还是到这一步了,可视化,我的超人!

FLTK是一个跨平台的轻量级 gui 库。该库本身是用 C++98 编写的,具有很高的可移植性。fltk crate 是用 Rust 编写的,并使用 FFI 调用 FLTK 包装器cfltk,它是用 C89 和 C++11 编写的。

虽然Rust里面不太兴面向对象编程,但是不可否认的是fltk却有浓浓的面向对象风格,不过这也要学了才知道的:

配置,Helloworld:

这个应该是有教学手册且最简单配置的rust GUI库,没有之一

话不多说直接Hello world:

[dependencies]
fltk = { version = "^1.2", features = ["fltk-bundled"] }
fn main() {let a = app::App::default();let mut wind = window::Window::new(100, 100, 800, 300, "Hello world");wind.end();wind.show();a.run().unwrap();
}

在这里插入图片描述

我们成功的利用fltk创建出了一个窗口

APP结构

crate在app模块提供一个App结构。初始化App结构会初始化所有内部样式,字体,支持的图像模型,运行的多线程换环境等等

App 结构允许您使用 with_scheme() 初始化程序设置应用程序的全局方案:

let c  = app::App::default().with_scheme(app::Scheme::Plastic);

在这里插入图片描述

官网给出了四种风格:Gtk,Basic、Plastic 和 Gleam等等。App是我们整个应用的承载。

Window

窗口是我们所有组件、图片的容器,FLTK 在它支持的每个平台上调用原生窗口,然后基本上是自己绘制(看来这个轮子不多,要自己画)。这意味着它在 Windows 上调用 HWND

关于窗口的定义请允许我重新展示一边:

let mut wind = window::Window::new(x, y, width, height, name);
  • x, 画出窗口后距离屏幕左侧的水平距离
  • y, 画出窗口后距屏幕顶部的垂直距离
  • width: 窗口的宽度
  • height: 窗口的高度
  • name: 窗口的名字,或者说title标题

窗口时可以嵌套的,我们嵌套窗口的方法:

use fltk::{prelude::*, *};fn main() {let app = app::App::default();let mut my_window = window::Window::new(100, 100, 400, 300, "My Window");let mut my_window2 = window::Window::new(10, 10, 380, 280, "");my_window2.set_color(Color::Black);// 关于end我会在下面写注释my_window2.end();my_window.end();my_window.show();app.run().unwrap();
}

在这里插入图片描述

窗口本身就是一个容器,容器之间的嵌套分子级父级关系的 。向我们上面的写法,我们只需主窗口调用end前定义,即可证明父子关系,这样对子组件的修饰甚至无需考虑执行顺序!,并且只需要主窗口调用show()即可。

    let mut my_window = window::Window::new(100, 100, 400, 300, "My Window");let mut my_window2 = window::Window::new(10, 10, 380, 280, "");my_window.show();my_window2.set_color(Color::Black);app.run().unwrap();

如果完完全全的分开两个窗口,不构建父子关系,那么会创建新的窗口,,

    let mut my_window = window::Window::new(100, 100, 400, 300, "My Window");my_window.show();let mut my_window2 = window::Window::new(10, 10, 380, 280, "");my_window2.set_color(Color::Blue);my_window2.show();

在这里插入图片描述

组件

fltk 提供了80多个组件,当然你让我去学完80多个组件不可能的好嘛

按钮:

let mut but = button::Button::new(160, 200, 80, 40, "Click me!");

钮的父级是 my_window,因为它是在隐式 begin() 和 end() 调用之间创建的。添加小部件的另一种方法是使用实现 GroupExt 特征的小部件提供的 add(widget) 方法:

let mut my_window2 = window::Window::new(10, 10, 380, 280, "");
my_window2.set_color(Color::Blue);
let but = button::Button::new(10,10,50,30,"button");
my_window2.add(&but);

按钮的 x 和 y 坐标是相对于包含该按钮的窗口的

此外,组件都可以使用构建器模式构建:

let but1 = Button::default().with_pos(10, 10).with_size(80, 40).with_label("Button 1");

对于这种可点击的组件,我们肯定是要绑定事件的:

let mut but = button::Button::new(10,10,50,30,"button");but.set_callback(move |_| {println!("Hello world");});

这样我们每点击一次按钮就会运行此函数

除了最基本的按钮,按钮还包括很多。我将展示其中几个按钮的效果(怎么有种上个世纪GUI的感觉):

  • LightButton:

    let mut but2 = button::LightButton::new(100,100,100,50,"button2");
    

    在这里插入图片描述

  • CheckedButton:

    let mut but2 = button::CheckButton::new(100,100,100,50,"button2");
    

    在这里插入图片描述

  • RoundButton:

    let mut but2 = button::RoundButton::new(100,100,100,50,"button2");
    

    在这里插入图片描述

需要注意的是,对于某些比如我想选的RoundButton或者说CheckedButton, 我们可以使用value查看选中的值:

println!("{}  {}",but2.value(),but3.value());
false  true

所以我们可以构建枚举与数据结构完成整个页面的数据收集:

// 目前只假设两个按钮的数据收集
#[derive(Debug)]
enum button_status{clicked(String),unclicked(Option<i32>),
}#[derive(Debug)]
struct checked{but1_status:button_status,but2_status:button_status,
}
//
impl checked {fn new(but1_value: button_status, but2_value:button_status) -> checked {checked{but1_status:but1_value, but2_status:but2_value}}
}fn main(){let app = app::App::default();let mut my_window = window::Window::new(100, 100, 400, 300, "My Window");let mut my_window2 = window::Window::new(10, 10, 380, 280, "");my_window2.set_color(Color::Blue);let mut but1 = button::RoundButton::new(100,100,100,50,"button1");let mut but2 = button::RoundButton::new(100,200,100,50,"button2");// 清除边框but1.clear_visible_focus();but2.clear_visible_focus();let mut but = button::Button::new(300,200,50,30,"Submit");my_window.show();but.set_callback(move |but| {let mut but1_ = button_status::unclicked(None);let mut but2_ = button_status::unclicked(None);if but1.value(){but1_ = button_status::clicked(but1.label());}if but2.value(){but2_ = button_status::clicked(but2.label());}let p = checked::new(but1_,but2_);println!("Data now: {:?}", p);});app.run().unwrap();
}
// 输出
Data now: checked { but1_status: unclicked(None), but2_status: clicked("button2") }

在这里插入图片描述

标签

FLTK没有标签部件,标签属于其他组件的自带部分。

FLTK标签非常的有意思,在某种程度上甚至有markdown的感觉,参见网址:https://fltk-rs.github.io/fltk-book/Labels.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CpbsvRPe-1653141672371)(https://www.fltk.org/doc-1.4/symbols.png)]

这个真的害挺好玩的。

菜单

菜单可以分为两种类型:选择型菜单与菜单栏

use fltk::{prelude::*, *};fn main() {let app = app::App::default();let mut wind = window::Window::default().with_size(400, 300);let mut choice = menu::Choice::default().with_size(80, 30).center_of_parent().with_label("Select item");let mut button= button::Button::new(150,200,100,70,"submit");choice.add_choice("Choice 1");choice.add_choice("Choice 2");choice.add_choice("Choice 3");// You can also simply type choice.add_choice("Choice 1|Choice 2|Choice 3");wind.end();wind.show();// 这种方法是由我们来处理回调button.set_callback(move |c| {match choice.choice(){Some(a) =>{println!("{}",a)},_ =>{println!("No chooesd");},}});app.run().unwrap();
}
Choice1

在这里插入图片描述

在其他的GUI假面中都会有信号机制,其实在fltk中也有。还记得我们学过的send 和 recv么,在这里也可以用起来啊

// 官网示例,跑过可以用
use fltk::{prelude::*, *};#[derive(Clone)]
enum Message {Choice1,Choice2,Choice3,
}fn main() {let a = app::App::default();let (s, r) = app::channel();let mut wind = window::Window::default().with_size(400, 300);let mut choice = menu::Choice::default().with_size(80, 30).center_of_parent().with_label("Select item");choice.add_emit("Choice 1",enums::Shortcut::None,menu::MenuFlag::Normal,s.clone(),Message::Choice1,);choice.add_emit("Choice 2",enums::Shortcut::None,menu::MenuFlag::Normal,s.clone(),Message::Choice2,);choice.add_emit("Choice 3",enums::Shortcut::None,menu::MenuFlag::Normal,s,Message::Choice3,);wind.end();wind.show();while a.wait() {if let Some(msg) = r.recv() {match msg {Message::Choice1 => println!("choice 1 selected"),Message::Choice2 => println!("choice 2 selected"),Message::Choice3 => println!("choice 3 selected"),}}}
}

这个add_emit,或者说sender机制目前只在菜单栏这里看到过,有大佬用过其他API欢迎补充。总之菜单差不多这样就OK啦

而菜单栏,就是一堆菜单对单一块的栏目就是菜单栏啦,

use fltk::{prelude::*, *};
use fltk::enums::{FrameType, Shortcut};fn main() {let a = app::App::default();let mut win = window::Window::new(300, 300, 800, 600, "New window");// 添加我们的菜单栏,这个很好理解我就不说了let mut menu = menu::SysMenuBar::default().with_size(800, 35);// 要使用frame布局,这是布局的一部分后面会讲到menu.set_frame(FrameType::FlatBox);// sender和receiver上面有let (s, r) = app::channel();menu.add_emit("&test1/test1a\t",Shortcut::Ctrl | 'a',menu::MenuFlag::MenuHorizontal,s.clone(),String::from("this is test1/test1a"),);menu.add_emit("&test1/test1b\t",Shortcut::empty(),menu::MenuFlag::Inactive,s.clone(),String::from("this is test1/test1b"),);menu.add_emit("&test2/test2a\t",Shortcut::empty(),menu::MenuFlag::Normal,s.clone(),String::from("this is test2/test2a"),);menu.add_emit("&test2/test2b\t",Shortcut::empty(),menu::MenuFlag::Normal,s.clone(),String::from("this is test2/test2b"),);menu.add_emit("&test2/test2c\t",Shortcut::empty(),menu::MenuFlag::Normal,s.clone(),String::from("this is test2/test2c"),);win.show();while a.wait(){match  r.recv(){Some(msg) =>{println!("{}",msg);},_ =>{continue}}}
}

Shoetcut主要是快捷键的设定,比如说:Shortcut::Ctrl | ‘a’, 就是用ctrl + a就能够唤醒的意思。menuflag主要是我们GUI显示的样式定义,比如menu::MenuFlag::MenuHorizontal显示快捷键啥的。这个页面长这个样子哦:

在这里插入图片描述

Input

Input就是文本框,没啥难的(简单示例):

fn main() {let a = app::App::default();let mut win = window::Window::new(300, 300, 800, 600, "New window");let mut input_area = input::Input::default().with_size(100, 30).with_label("input your name").center_of_parent();input_area.set_value("None");let mut but = Button::new(350,500,100,50,"submit");win.show();but.set_callback(move |but|{println!("Your name is {}", input_area.value());// input_area.set_readonly(true);});a.run().unwrap();
}

在input中有一些好用的方法,比如:output是一个无法编辑的文本展示框,或者使用Input。set_readonly等方法

注意,无论Input的何种其他变体,我们开发者,或者说程序读到的都是字符串类型而不是其他类型

Valuator

说实话,我并不知道这个组件怎么称呼比较合适。Valuator包含滑块,滚动条一类的可以拖拽调节的东西:

use fltk::{prelude::*, *};
use fltk::button::Button;
use fltk::enums::{FrameType, Shortcut};fn main() {let a = app::App::default();let mut win = window::Window::new(300, 300, 800, 600, "New window");let mut border = valuator::ValueSlider::new(200,200,50,300,"Slider");// 设置滚动条的最大与最小值border.set_maximum(100.0);border.set_minimum(0.0);// 滚动条每次变化以1为单位border.set_step(1.0,1);// 初识位置为20,下同border.set_value(20.0);let mut c = valuator::Counter::new(400,200,200,50,"Counter");c.set_value(0.8);let mut d = valuator::Dial::new(400,400,100,100,"Dial");d.set_maximum(100.0);d.set_minimum(0.0);d.set_step(0.5,1);let mut e = valuator::Adjuster::new(600,0,200,100,"adjuster");let mut f = valuator::FillSlider::new(0,0,200,100,"FillSlider");d.set_callback(move |d|{println!("{}", d.value());});e.set_callback(move |e|{println!("{}", e.value());});win.show();a.run().unwrap();
}

在这里插入图片描述

讲道理看着玩玩害挺不错,这一节也没有其他特别要注意的点,自己动手试试API挺好玩的

Text

主要目的是显示和编辑文本,需要TextBuffer缓冲区缓冲文本,因为肯定会涉及到文档保存的。

use fltk::{prelude::*, *};fn main() {let a = app::App::default();let mut buf = text::TextBuffer::default();let mut win = window::Window::default().with_size(800, 700).with_label("Editor");let mut txt = text::TextEditor::default().with_size(790, 590).center_of_parent();let mut button = button::Button::new(350,650,100,50,"Submit");txt.set_buffer(buf.clone());win.end();win.show();buf.set_text("Hello world!\nThis is a text editor!");button.set_callback(move |button|{println!("Do you want to save {}", buf.text());});a.run().unwrap();
}

我们可以使用一些DisplayExe提供的方法为我们的文本框添加一些更绚丽的效果。我们TextBuffer的作用不仅是缓冲数据,更可以缓冲样式

不过官网的例子导师有些花里胡哨了,我简单的更改字体与颜色

txt.set_buffer(buf);
txt.set_text_font(Font::Courier);
txt.set_text_size(16);

各种设置可以参见这里:https://docs.rs/fltk/latest/fltk/prelude/trait.DisplayExt.html#tymethod.style_buffer

fn main() {let a = app::App::default();let mut buf = text::TextBuffer::default();let mut sbuf = text::TextBuffer::default();let mut win = window::Window::default().with_size(400, 300);let mut txt = text::TextEditor::default().with_size(390, 290).center_of_parent();// 这里用clone才能追踪到buf的变化。txt.set_buffer(buf.clone());txt.set_text_font(Font::Courier);txt.set_text_size(16);win.end();win.show();let mut p = 0;while a.wait(){// 每换一行就会改变颜色的小玩具let h = buf.text().lines().count() % 2;if h == 1{txt.set_text_color(Color::Blue);}else{txt.set_text_color(Color::Black);}}
}

在这里插入图片描述

Browser

此浏览器非我们上网用的浏览器,更像是任务管理器之流的浏览器,最要是有点类似表格一样的使用。

//官网的代码,演示的代码确实有点潦草可以理解:
use fltk::{prelude::*, *};fn main() {let app = app::App::default();let mut win = window::Window::default().with_size(900, 300);let mut b = browser::Browser::new(10, 10, 900 - 20, 300 - 20, "");let widths = &[50, 50, 50, 70, 70, 40, 40, 70, 70, 50];b.set_column_widths(widths);b.set_column_char('\t');// we can now use the '\t' char in our add method.b.add("USER\tPID\t%CPU\t%MEM\tVSZ\tRSS\tTTY\tSTAT\tSTART\tTIME\tCOMMAND");b.add("root\t2888\t0.0\t0.0\t1352\t0\ttty3\tSW\tAug15\t0:00\t@b@f/sbin/mingetty tty3");b.add("erco\t2889\t0.0\t13.0\t221352\t0\ttty3\tR\tAug15\t1:34\t@b@f/usr/local/bin/render a35 0004");b.add("uucp\t2892\t0.0\t0.0\t1352\t0\tttyS0\tSW\tAug15\t0:00\t@b@f/sbin/agetty -h 19200 ttyS0 vt100");b.add("root\t13115\t0.0\t0.0\t1352\t0\ttty2\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty2");b.add("root\t13464\t0.0\t0.0\t1352\t0\ttty1\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty1 --noclear",);win.end();win.show();app.run().unwrap();
}

在这里插入图片描述

browser特效格式写法参见:https://fltk-rs.github.io/fltk-book/Browsers.html


http://chatgpt.dhexx.cn/article/rcPJUvOy.shtml

相关文章

Visual Studio 安装 FLTK

Visual Studio 安装 FLTK 环境介绍 Windows 10Visual Studio Community 2019 (2021-11-29补充2022版)FLTK-1.3.7 下载与解压 ​ 进入FLTK官网-Download下载最新版本。 ​ 解压到D:\Program Files\fltk(解压路径任意都行)&#xff0c;推荐使用Bandzip免费解压工具。 编译 …

FLTK--轻量级C++跨平台GUI库

FLTK FLTK&#xff08;Fast Light Toolkit&#xff09;是一个跨平台的CGUI工具集&#xff0c;用在UNIX/Linux&#xff08;X11&#xff09;、微软Windows和Mac OS X上。FLTK提供现代的GUI功能&#xff0c;除却膨胀&#xff0c;通过OpenGL和内建的GLUT模拟器提供3D图形支持。最初…

浅谈如何fltk项目编译和实现显示中文

目录 一、编译 二、中文显示如何处理&#xff1a; 2.1在发文2天前突然发现&#xff0c;我这个界面显示英文出现问题了&#xff0c;开始我的搜索之旅&#xff0c;一些参考页面有碰到问题也可以看看&#xff1a; 2.2、 那就开始翻翻官方自带的例程吧&#xff0c;看看他如何显…

FLTK 学习一:简介和安装

文章目录 FLTK 简介FLTK 安装FLTK Windows安装FLTK Linux 安装 FLTK 简单示例参考资料 FLTK 简介 从网上引用的一段 FLTK 的介绍 FLTK (Fast Light Tool Kit 发音为fulltick) 是一种使用 C 开发的 GUI 工具包&#xff0c;它可以应用于 Unix, Linux, MS-Windows95/98/NT/2000 和…

安装使用FLTK图形库

FLTK是Fast Light Toolkit的简称&#xff0c;是一个跨平台的C GUI包&#xff0c;FLTK提供xiandai GUI功能&#xff0c;而且通过OpenGL支持3D图像。 下载FLTK安转包fltk-1.3.4-1-source.tar.gz&#xff1a; http://www.fltk.org/software.php?VERSION1.3.4&FILEfltk/1.3.…

BOBCAT: 基于双层优化的计算机化自适应测验(超硬核解读论文+阅读论文技巧)

文章目录 前言AbstractIntroductionCAT 介绍传统的认知诊断模型传统的CAT选题策略传统方法局限性 ContributionsBOBCAT框架双层优化问题BOBCAT框架BOBCAT 训练过程 OptimizationExperiments能力评估问题暴露和内容重叠问题选择 Conclusions 前言 大家好&#xff0c;我是小曾&a…

项目管理理论与实践(3)——如何进行有效的项目管理

对于具有成功并有效的项目管理经验的项目经理&#xff0c;还是非常难得的。因为项目管理并不是一件很简单的事情。虽然自己对于项目管理的理解还是处于初级阶段&#xff0c;但是利用自己学习到的理论知识&#xff0c;还是想做一次归纳&#xff0c;希望对大家能够受用。那么就开…

计算机自适应考试技巧,计算机自适应题库实现

在软件的开发中,基于题库的计算机自适应考试已成为一个重要的发展方向,而计算机自适应题库的建立就显得尤为重要。计算机自适应测验(Computerized Adaptive Testing,简称CAT)是近年来发展起来的一种新的测验形式。这种测验以项目反应理论为基础,以计算机技术为手段,在题库…

项目经理都会面临什么问题?

最近手里一个项目接近尾声&#xff0c;还有一个项目正在初期调研&#xff0c;无缝衔接&#xff0c;原定结项之后的3天假期也泡汤了&#xff0c;每一个环节都出问题我真的会心累&#xff0c;再加上最近组里人事变动&#xff0c;也没有及时做好复盘&#xff0c;客户又出现了临时需…

反应-扩散方程(Reaction-diffusion system)

文章目录 1. 单组分反应-扩散方程2. 双组分反应-扩散方程3. 三组分和更多组分的反应-扩散方程4. Fishers equation4.1 KPP方程 5. Belousov–Zhabotinsky reaction5.1 历史5.2 化学机理5.2.1 变体 5.3 Noise-induced order5.3.1 数学背景 6. Briggs–Rauscher reaction7. ZFK e…

项目延期的因素有哪些?项目经理应该如何应对

项目延期是项目管理中常见的问题之一&#xff0c;也是管理者最头疼的问题。项目延期的出现可能是由于以下原因&#xff1a; 1、工作中突发事件多&#xff1a;在评估工作量时&#xff0c;通常会基于过往的经验来进行评估&#xff0c;但由于信息社会中各种信息随处可见&#xf…

项目管理中影响项目进度的原因及解决方法

项目管理中对工期的控制主要是进度控制&#xff0c;在项目进行过程中&#xff0c;由于项目时间跨度长&#xff0c;人员繁杂&#xff0c;如果管理不规范&#xff0c;就容易导致项目进度滞后&#xff0c;如何管理好施工进度是管理者需要解决的问题之一。 1、项目计划缺乏执行力…

图解PMP项目管理马斯洛需求层次理论在公司管理中的应用!

马斯洛的需求层次结构是心理学中的激励理论&#xff0c;包括人类需求的五级模型&#xff0c;通常被描绘成金字塔内的等级。 从层次结构的底部向上&#xff0c;需求分别为&#xff1a;生理&#xff08;食物和衣服&#xff09;&#xff0c;安全&#xff08;工作保障&#xff09;…

php 项目反应理论,科学网—好文 | 纽约石溪大学:机器学习中基于项目反应理论的集成学习 - 陈培颖的博文...

机器学习中&#xff0c;研究者们对分类集成的关注与日俱增&#xff0c;尤其关注分类精度的提升。IJAC近期发表了来自纽约石溪大学研究者的最新成果&#xff0c;该研究基于项目反应理论&#xff0c;提出一种加权投票方法---基于IRT理论的集成学习算法&#xff0c;该方法可正确处…

项目反应理论 EM估计

项目反应理论参数的EM估计 写在前面&#xff1a; 本文主要描述了整个IRT使用EM算法参数的估计过程&#xff0c;其中涉及大量公式&#xff0c;如只是需要了解IRT相关基础知识&#xff0c;请转战wiki&#xff5e;&#xff5e; 预警&#xff1a; 大量公式来袭&#xff5e;&#…

项目反应理论

项目反应理论(item response theory)是属于心理学中认知诊断常用的一种理论,即根据被测试者针对某个问题的答案来对被测者的认知状况进行估计。“项目”实质就是测试题,“反应”就是被测者的答案。也有学者称项目反应理论也是机器学习中的一个类别,即根据被测者对测试题的…

密码校验密码正则校验,密码表单校验总结

一.前言&#xff0c;日常开发中&#xff0c;表单校验是出现率非常高的一个需求&#xff0c;特别是密码校验。本文就针对常见的几种密码校验&#xff08;含正则&#xff09;做个总结&#xff0c;做个共享。 二. 密码必须包含数字&#xff0c;字母和特殊符号。 写法&#xff1a;…

正则表达式-几种常见的密码校验

原文&#xff1a;https://jingyan.baidu.com/article/5bbb5a1b634cca53eba179ce.html 首先说一下密码必须是6~18位之间的数字&#xff0c;正则表达式为"^[0-9]{6,18}$"&#xff0c;其中[0-9]表示必须是数字&#xff0c;{6,18}表示必须在6到18位之间&#xff0c;代码如…

【算法】程序猿必备算法

文章目录 快速排序算法堆排序算法归并排序二分查找算法BFPRT(线性查找算法)DFS&#xff08;深度优先搜索&#xff09;BFS(广度优先搜索)Dijkstra算法动态规划算法朴素贝叶斯分类算法Floyd Warshall算法贝尔曼福特算法贪心算法拓扑排序最小生成树分治算法KMP暴力匹配更多来源 快…

数据结构+算法=程序

&#xff08;1&#xff09; 数据结构算法程序。 每个学计算机的人都听过这个公式。 这个公式是尼克劳斯沃斯在1976年出版《算法数据结构&#xff1a;程序》一书中提出。尼克劳斯沃斯还是Pascal编程语言的发明人&#xff0c;而且他还在1973年出版《系统程序设计导论》一书中提出…