rust fltk-rs 界面编程一个小例子

rust 性能出色,但其gui库并不是很多,成熟的就更少了,而fltk-rs作为fltk rust语言的绑定,基本是够用的。本文描述了一个fltk-rs 编程的一个小例子,代码如下:

main.rs

#![windows_subsystem = "windows"]
#[allow(dead_code)]
#[warn(unreachable_patterns)]
use fltk::{
    App,
    enums::{FrameType, *},
    frame::Frame,
    image::{SharedImage, SvgImage},
    prelude::*,
    window::Window,
    *,
};
use fltk::{
    button::Button,
    group::Flex,
    text::{TextBuffer, TextEditor},
};
use reqwest::Error;
// use opener;
use std::time::Duration;
use std::{process::Command, thread};
fn main() {
    let app = app::App::default().with_scheme(app::Scheme::Gtk);
    app::background(230, 230, 230);
    let (width, _height) = app::screen_size();
    let mut wind = Window::new(100, 100, 800, 600, "fltk test 04").center_screen();
    //窗口关闭事件
    wind.set_callback(|_| {
        let (width, height) = app::screen_size();
        if app::event() == enums::Event::Close {
            let dialog = dialog::choice2(
                ((width / 2.0) as i32) - 200,
                ((height / 2.0) as i32) - 100,
                "确定退出吗?",
                "否",
                "是",
                "取消",
            )
            .unwrap();
            println!("dialog: {}", dialog);
            if dialog == 1 {
                app::quit();
                std::process::exit(0);
            }
        }
    });
    //图标
    wind.set_icon(Some(SvgImage::load("screenshots/logo.svg").unwrap()));
    let mut menu = menu::MenuBar::default().with_size(800, 35);
    menu.set_frame(FrameType::FlatBox);
    menu.add(
        "文件/新建\t",
        Shortcut::Ctrl | 'n',
        menu::MenuFlag::Normal,
        menu_cb,
    );
    menu.add(
        "文件/保存\t",
        Shortcut::Ctrl | 'w',
        menu::MenuFlag::Normal,
        menu_cb,
    );
    menu.add(
        "文件/退出\t",
        Shortcut::Ctrl | 'x',
        menu::MenuFlag::Normal,
        menu_cb,
    );
    menu.add(
        "编辑/改写\t",
        Shortcut::None,
        menu::MenuFlag::Normal,
        menu_cb,
    );
    menu.add(
        "编辑/字句\t",
        Shortcut::None,
        menu::MenuFlag::Normal,
        menu_cb,
    );
    menu.add(
        "编辑/规则\t",
        Shortcut::None,
        menu::MenuFlag::Normal,
        menu_cb,
    );
    let mut frame = Frame::new(10, 50, 780, 60, "");
    frame.set_frame(FrameType::EngravedBox);
    let mut btn1 = Button::new(20, 70, 60, 30, "@< 开始");
    let mut btn2 = Button::new(90, 70, 60, 30, "@>| 结束");
    btn2.set_frame(FrameType::GleamUpBox);
    let flex = Flex::new(220, 70, 120, 30, "").column();
    let mut choice_thread = menu::Choice::default().with_label("多线程");
    for i in 1..10 {
        choice_thread.add_choice(&i.to_string());
    }
    //设置默认值
    choice_thread.set_value(6);
    //获取默认值
    println!("{}", choice_thread.value() + 1);
    //监听
    choice_thread.set_callback(|c| {
        let v = c.value();
        match v {
            v => println!("{} is selected!", v + 1),
        }
    });
    flex.end();
    let mut btn_img = Button::new(350, 60, 340, 40, None);
    btn_img.set_frame(FrameType::NoBox);
    // 设置程序图标
    let mut image = SharedImage::load("screenshots/logo.png").unwrap();
    image.scale(240, 50, true, true);
    btn_img.set_image(Some(image));
    //  button tooltip message
    btn_img.set_tooltip("点击访问官方网页");
    //打开网址
    btn_img.set_callback(|_| {
        let url = "https://www.lanhong-vip.com";
        Command::new("cmd.exe")
            .args(["/C", "start", url])
            .output()
            .expect("调用失败");
    });
    // let mut btn3 = Button::new(710,70,60,30,"@<- 退出");
    let mut frame2 = Frame::new(10, 120, 780, 320, "");
    frame2.set_frame(FrameType::EngravedBox);
    let flex2 = Flex::new(20, 140, 760, 280, "").column();
    let mut text1 = TextEditor::default().center_of(&flex2);
    let buffer = TextBuffer::default();
    let buffer2: TextBuffer = buffer.clone();
    text1.set_buffer(buffer.clone());
    flex2.end();
    let width = (width / 1.0) as i32;
    let mut frame3 = Frame::new(50, 450, 700, 60, "");
    frame3.set_frame(FrameType::EngravedBox);
    let input_url = input::Input::new(100, 465, 400, 30, "网址:");
    let mut choice_encode = menu::Choice::new(520, 465, 100, 30, "");
    choice_encode.add_choice("选择编码");
    choice_encode.add_choice("utf-8");
    choice_encode.add_choice("gbk");
    choice_encode.set_value(0);
    let mut btn_submit = button::Button::new(630, 465, 60, 30, "@> 提交");
    btn_submit.set_callback(move |btn_submit| {
        let mut btn_sumbit_clone = btn_submit.clone();
        let mut value = input_url.value().trim().to_string();
        if value.len() == 0 {
            value = "是空的".to_string();
            dialog::message_title_default("提示");
            dialog::alert(
                width / 2 - 200,
                width / 4 - 100,
                &format!("你输入的是:\t{}", value),
            );
        } else {
            let mut buffer2 = buffer2.clone();
            btn_sumbit_clone.deactivate();
            let charset_index = choice_encode.value();
            let mut charset = "utf-8";
            if charset_index == 0 || charset_index == 1 {
                charset = "utf-8";
            } else if charset_index == 2 {
                charset = "gbk";
            }
            thread::spawn(move || {
                let res = get_content_by_url(&value, &charset);
                match res {
                    Ok(r) => buffer2.set_text(&r),
                    Err(e) => buffer2.set_text(&e.to_string()),
                }
                btn_sumbit_clone.activate();
            });
        }
    });
    let flex3 = Flex::default().column().center_of_parent();
    flex3.end();
    let mut frame4 = Frame::new(0, 580, width, 320, "");
    frame4.set_frame(FrameType::EngravedBox);
    let mut label1 = Button::new(0, 580, 40, 20, "状态栏");
    label1.set_frame(FrameType::NoBox);
    let mut status_bar_text = Button::new(150, 580, 450, 20, None);
    status_bar_text.set_frame(FrameType::NoBox);
    status_bar_text.set_align(Align::Left);
    status_bar_text.set_label_color(Color::Blue);
    //必须克隆一个btn2,否则会涉及到多次借用,编译不通过
    let mut bt2 = btn2.clone();
    let mut bt1 = btn1.clone();
    btn1.set_callback(move |btn1| match btn1.value() {
        false => {
            let mut b = buffer.clone();
            let mut status = status_bar_text.clone();
            let mut text_area = text1.clone();
            let c = btn1.clone();
            let mut btn1_1 = btn1.clone();
            let mut btn2_2 = bt2.clone();
            bt2.activate();
            btn1.deactivate();
            //多线程
            thread::spawn(move || {
                for i in 1..10000 {
                    //停止标志
                    if c.active() {
                        break;
                    }
                    let st = "第".to_owned() + &(i.to_string()) + "个";
                    status.set_label(&st);
                    b.append(&(i.to_string() + "-添加生成的内容\n"));
                    thread::sleep(Duration::from_nanos(0));
                }
                //一直往下滚动
                let line = b.text().split("\n").count().try_into().unwrap();
                text_area.scroll(line, 1);
                btn1_1.activate();
                btn2_2.deactivate();
            });
        }
        true => {
            bt2.deactivate();
            bt1.activate();
        }
    });
    btn2.set_callback(move |btn2| match btn2.value() {
        false => {
            btn1.activate();
            btn2.deactivate();
        }
        true => {
            btn1.deactivate();
            btn2.activate();
        }
    });
    let flex4 = Flex::new(0, 580, width, 40, "").column();
    flex4.end();
    wind.make_resizable(true);
    wind.end();
    wind.show();
    app.run().unwrap();
}
/**
 * 菜单事件监听
 */
fn menu_cb(m: &mut impl MenuExt) {
    dialog::message_title_default("退出程序?");
    if let Some(choice) = m.choice() {
        //匹配每个菜单项
        let (width, height) = app::screen_size();
        match choice.as_str() {
            "新建\t" => println!("New"),
            "退出\t" => {
                //居中显示x,y参数是关键
                let dialog = dialog::choice2(
                    (width / 2.0) as i32 - 200,
                    (height / 2.0) as i32 - 100,
                    "确定退出吗?",
                    "否",
                    "是",
                    "取消",
                )
                .unwrap();
                if dialog == 1 {
                    app::quit();
                }
            }
            _ => println!("{}", choice),
        }
    }
}
fn get_content_by_url(url: &str, charset: &str) -> Result<String, Error> {
    let r = reqwest::blocking::get(url);
    //异常处理
    match r {
        Ok(re) => {
            let res = re.text_with_charset(charset).unwrap();
            let document = scraper::Html::parse_document(&res);
            let title_select = document.root_element();
            Ok(title_select.html())
        }
        Err(e) => Err(e),
    }
}

 

cargo.toml 内容
[package]
name = "test_04"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
fltk = "*"
reqwest = {version ="0.11",features = ["blocking",'json']}
scraper = "*"

 

最终界面如下:
rust fltk-rs 界面编程一个小例子

相关文章

发表回复

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




Enter Captcha Here :

qq
微信
微信
分享本页
返回顶部