前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Rust Druid 之Menu菜单栏

Rust Druid 之Menu菜单栏

原创
作者头像
8菠萝
修改2021-05-28 14:36:14
1.6K1
修改2021-05-28 14:36:14
举报
文章被收录于专栏:菠萝上市没有菠萝上市没有

概念

GUI有两种菜单类型, 一种是菜单栏,另一种是右键菜单列表。

在Druid中这两种菜单都由Menu类型来指定。

窗口菜单栏通过WindowDesc::menu() 方法来绑定。

右键菜单栏通过Controller中的右键事件EventCtx::show_context_menu()来展示。

Menu的事件触发使用 on_activate() 来绑定事件逻辑处理, 可用在该函数中操作数据对象或者向其他组件发送消息。

Menu 中还有:

pub fn refresh_on(mut self, refresh: impl FnMut(&T, &T, &Env) -> bool + 'static);

pub fn rebuild_on(mut self, rebuild: impl FnMut(&T, &T, &Env) -> bool + 'static);

用于菜单栏变动的更新。

实践

通过一个菜单栏读入文件到TextBox,通过右键菜单来清空TextBox读入的内容。

Cargo.toml

[dependencies]

druid = { git = "https://github.com/linebender/druid.git", features=["image", "png"]}

代码语言:javascript
复制
use std::fs::File;
use std::io::Read;

use druid::Event;
use druid::LocalizedString;
use druid::WidgetExt;
use druid::widget::Controller;
use druid::{lens, Env, FileDialogOptions, MenuItem, WindowId};
use druid::{widget::TextBox, AppLauncher, Menu, Widget, WindowDesc};
use druid::{AppDelegate, Command, Data, FileSpec};

#[derive(Data, Clone)]
struct AppData {
    data: String,
}

struct MenuDelegate;

// 处理菜单栏传来的打开文件的Command命令
impl AppDelegate<AppData> for MenuDelegate {
    fn command(
        &mut self,
        ctx: &mut druid::DelegateCtx,
        target: druid::Target,
        cmd: &druid::Command,
        data: &mut AppData,
        env: &Env,
    ) -> druid::Handled 
    {
        if let Some(e) = cmd.get(druid::commands::OPEN_FILE) {
            let mut f = File::open(e.path()).expect("Open File Fail");
            f.read_to_string(&mut data.data).expect("Read Fail");
            return druid::Handled::Yes;
        }
        return druid::Handled::No;
    }
}


// 处理右键菜单事件
struct EditController;
impl <W:Widget<AppData>> Controller<AppData, W> for EditController {
    fn event(&mut self, child: &mut W, ctx: &mut druid::EventCtx, event: &Event, data: &mut AppData, env: &Env) {
        if let Event::MouseDown(e) = event  {
            if e.button.is_right() {
                // 展示菜单
                ctx.show_context_menu(make_context_menu(), e.pos);
            }
        }
        child.event(ctx, event, data, env)
        }
}


fn make_window() -> impl Widget<AppData> {
    let data = lens!(AppData, data);
    let text = TextBox::new().lens(data).expand().controller(EditController{});
    text
}


// 菜单栏
fn make_menu(_: Option<WindowId>, data: &AppData, _: &Env) -> Menu<AppData> {
    let mut menu = Menu::empty();
    let mut menu_file = Menu::new("File");

    let txt = FileSpec::new("Text file", &["txt"]);
    let save_dialog_options = FileDialogOptions::new()
        .allowed_types(vec![txt])
        .default_type(txt)
        .name_label("Target")
        .title("OpenFile")
        .button_text("Open");
	//  菜单处理事件,这里是发送打开文件的Command
    let menu_open_act = MenuItem::new("Open").on_activate(move |ctx, _data: &mut AppData, _env| {
        ctx.submit_command(druid::commands::SHOW_OPEN_PANEL.with(save_dialog_options.clone()));
    });

    menu_file = menu_file.entry(menu_open_act);
    menu = menu.entry(menu_file);
    menu
}

// 右键菜单
fn make_context_menu()->Menu<AppData>{
    Menu::empty()
    .entry(MenuItem::new(LocalizedString::new("clear")).on_activate(|_ctx, data:&mut AppData, _env|{
        data.data.clear();
    }))
}


fn main() {
    // window 绑定菜单栏
    let window = WindowDesc::new(make_window()).menu(make_menu);
    AppLauncher::with_window(window)
        .log_to_console()
        .delegate(MenuDelegate{})
        .launch(AppData {
            data: String::new(),
        })
        .unwrap();
}

菜单栏
菜单栏

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概念
  • 实践
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档