FLTK-Rs

2023-05-16

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FLTK-Rs 的相关文章

  • MySQL修改数据表中的字段名

    MySQL修改数据表中的字段名 在一张数据表中只能设置一个唯一名称的字段名 在同一张数据表中 xff0c 不能出现两个名称完全相同的字段名 因此 xff0c 数据库系统可以通过字段名来区分数据表中的不同字段 在MySQL中 xff0c AL
  • 证明:当gcd(a, b) = 1,则gcd(a + b, a) = 1

    假设 xff1a gcd a b 61 1 证明 xff1a gcd a 43 b b 61 1 反证法 xff1a 假设gcd a 43 b b 61 k 61 1 则 xff1a b 61 k r1 a 43 b 61 a 43 k r
  • 实战microPython(二)时钟和日历的使用

    实战microPython 2 时钟和日历的使用 David Zou 创客DIY乐园 对于一名创客 xff0c 自制一个个性化的时钟或闹钟啥的 xff0c 应该是比较常见的入门级任务了 通常我们制作时钟或闹钟的时候 xff0c 都需要借助专
  • 实战microPython(10)-蓝牙模块的使用

    实战microPython 10 蓝牙模块的使用 David Zou 2018 12 27 本文讲解蓝牙模块的使用 xff0c 以及通过uPyBoard来操作蓝牙模块并实现手机和uPyboard互动 正在学习和使用uPyBoard开发的小伙
  • nohup: failed to run command ‘java’: No such file or directory解决方案

    场景 xff1a Jekins实现自动化部署 问题描述 Jekins打包后端项目后发送Jar到对应的应用服务器 xff0c 通过应用服务器Shell脚本启动服务报错 nohup span class token operator span
  • System.DllNotFoundException: 无法加载DLL

    问题描述 使用VS2005在Windows Server 2003上编译C 43 43 代码 输出dll文件 把该dll放到运行机器 与编译机器的系统完全一致 上 供C 代码 web前台 调用 提示无法加载dll 分析 1 路径完全没有问题
  • Flutter学习(一)

    开始学习 为什么使用 Fultter xff1f 为什么使用 Fultter xff1f 言归正传 xff0c 亘古不变环境搭建 xff1a Android Studio 下载 xff0c 我的是这个版本 xff0c emmmm 首先安装g
  • 树莓派 ubuntu18.04 mate更换为国内镜像源

    文章目录 前言正文参考 前言 我使用树莓派3B 43 xff0c 烧写的操作系统为ubuntu mate18 04 网上的相关教程很多 xff0c 但说的很详细的不多 xff0c 本文算是做一个简单的整理 树莓派采用的是arm架构 xff0

随机推荐

  • Spring常见面试题总结(超详细回答)

    1 Spring是什么 Spring是一个轻量级的IoC和AOP容器框架 是为Java应用程序提供基础性服务的一套框架 xff0c 目的是用于简化企业应用程序的开发 xff0c 它使得开发者只需要关心业务需求 主要包括以下七个模块 xff1
  • 在android studio中使用kotlin

    一 安装kotlin插件 二 导入Kotlin的核心库及其扩展库Anko库 1 在项目根目录下的build gradle文件中指定kotlin插件的版本及路径 buildscript ext kotlin version 61 span c
  • sublime Text SFTP LICENSE 注册码

    34 email 34 34 xiaosong 64 xiaosong me 34 34 product key 34 34 d419f6 de89e9 0aae59 2acea1 07f92a 34 这个就是SFTP注册码 将上面的代码复
  • Aliddns插件使用:小白超详细图文教程

    Aliddns插件使用 xff1a 小白超详细图文教程 Aliddns插件 xff0c 用阿里的云解析速度是快 xff0c 天下武功为快不破 作为一个小白的我 xff0c 看这篇帖子也是一脸懵逼 xff0c http koolshare c
  • 在PyQt5中使用多进程(multiprocessing)

    multiprocessing对象要放在 main 所在的启动文件使用槽连接multiprocessing对象 import sys from multiprocessing import Pool from PyQt5 QtWidgets
  • go使用exec执行命令

    golang exec 命令执行
  • 【汇编】AT89C52点亮一盏LED灯(汇编语言)

    学习利用汇编语言写单片机程序的第一步是要学习汇编语言的相关理论知识 xff0c 那么实践操作的第一步肯定是从点灯开始啦 xff01 编译环境 xff1a keil4 编译语言 xff1a 汇编语言 内容 xff1a 一 keil4建立AT8
  • wsl-常见问题

    基于wsl2的docker如何迁移镜像文件 默认基于wsl2的docker desktop的镜像是有wsl2管理的 xff0c 而wsl2一般在c盘 当下载的镜像多了之后 xff0c 就会把C盘爆满 wsl shutdown wsl exp
  • 求0-7所组成的奇数个数

    include lt stdio h gt include lt stdlib h gt main long sum 61 4 long s 61 4 int j for j 61 2 j lt 61 8 j 43 43 printf 34
  • UITabBarController详解

    一 UITabBarController简介 一 继承关系 UITabBarController和UINavigationController类似 xff0c 也继承于UIViewController xff0c 也可以轻松地管理多个控制器
  • 关于多卡Android设备获取手机号的研究

    首先我们都知道如何获取Android手机的Sim手机号 fun getNativePhoneNumber context Context String val tm 61 context getSystemService Context T
  • 【入门学习三】基于 FPGA 使用 Verilog 实现按键状态机代码及原理讲解

    目录 一 状态机二 模块设计三 代码实现四 管脚配置及结果展示 上一篇博文 xff1a 入门学习二 基于 FPGA 使用 Verilog 实现蜂鸣器响动的代码及原理讲解 概述 xff1a 前面的两篇文章 xff0c 其中按键模块采用的是延时
  • 【二分】洛谷_3902 递增

    题意 给出n个数 xff0c 求出修改最少的数字 xff0c 使得数列严格单调递增 思路 我们用一个数组s来记录当前存到的数字 xff0c 每次放进一个数字 xff0c 我们就判断它是不是比之前的数小 xff0c 否则我们就二分找到一个最好
  • 使用mysql语句进行分组查询

    使用mysql语句进行分组查询 1 作用 对整个数据表的某几个字段进行分组 然后通过分组函数得到我们想要的结果 2 如何用 2 1 只分一个组 2 1 1 本质 就是根据分组字段把整个表的数据分为几组 然后分别对每组里面的数据进行汇总查询或
  • 删除流氓软件 Alibaba PC Safe Service

    好久没用笔记本了 xff0c 之前被人再用 xff0c 今天偶尔想用下 xff0c 开机遇到两件恶心到家的事情 xff0c 第一件 xff0c 360弹窗 xff0c 不停的显示 xff0c 感觉特别烦就卸载了360所有的东西 xff1b
  • 枚举类型字符化输出的方法

    方法一 xff1a 用函数 xff08 简单的应用场景下 xff09 方法二 xff1a 用字符串转换 创建枚举类型 enum athleteName WANG ZHOU SU CHO KIM LI MIRE BOUTIN 创建结构体 st
  • 【单片机竞赛:共阳数码管静态控制】

    51单片机 xff08 国信天长单片机实训平台 xff09 基于keli的常用程序之 共阳数码管一般静态控制程序设计 文章目录 51单片机 xff08 国信天长单片机实训平台 xff09 基于keli的常用程序之 共阳数码管一般静态控制程序
  • Linux - 搭建LDAP统一认证服务

    目的 通过以下步骤最终可使用ldap server中的用户登录一台ldap client xff0c 并允许有sudo权限 平常公司中所用的域账号以及服务器账号也许就是使用如下方式 xff0c 但是应该没有这么简陋 xff0c 只是借机了解
  • 每日练习------有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面的m个数

    题目 有n个整数 xff0c 使其前面各数顺序向后移m个位置 xff0c 最后m个数变成最前面的m个数 解题关键 需要新建个数组使得原数组可以做到整体往后移动M位 思路 1 创建个有n个整数的数组 2 输出n个数字 存储到数组中 3 遍历原
  • FLTK-Rs

    终于还是到这一步了 xff0c 可视化 xff0c 我的超人 xff01 FLTK是一个跨平台的轻量级 gui 库 该库本身是用 C 43 43 98 编写的 xff0c 具有很高的可移植性 fltk crate 是用 Rust 编写的 x