当前位置: 首页 > news >正文

【Tauri2】010——菜单menu(1)

目录

前言

直接创建

菜单项——MenuItem

使用new方法

with_id方法

 子菜单——SubMenu

new方法

with_id方法

with_items方法

菜单——Menu

间接创建

在前端创建菜单

总结


前言

前面介绍了setup这个hook。也提到了菜单,这篇来试试创建菜单以及菜单的动作(action)

在Rust中创建菜单/

直接创建

在创建之前,可以进行一些其他操作。

首先,将lib.rs中的run函数的内容复制到main.rs,其他的东西也复制,删除lib.rs

再删除Cargo.toml下的表lib,创建menu.rs

实际上,可以不分开,但是,所有代码都写在一起,不好看。

从小到大创建。

菜单项——MenuItem

MenuItem in tauri::menu - Rusthttps://docs.rs/tauri/2.4.0/tauri/menu/struct.MenuItem.html

使用new方法

可以使用new方法,看看函数签名

  pub fn new<M, T, A>(
    manager: &M,
    text: T,
    enabled: bool,
    accelerator: Option<A>,
  ) -> crate::Result<Self>

这个签名总体上看,四个参数,三个泛型,返回Result<Self>

Manager:&App或者&Apphandle

Text:文本。

enabled:能否使用

accelerator:快捷键

笔者以前还没发现,这个Result,居然是别名

pub type Result<T> = std::result::Result<T, Error>;

怪不得,用起来有点怪。

因此,创建菜单栏的代码如下

 let start=MenuItem::new(app, "start", true,  Some("q"))?;

或者没有快捷键

let start=MenuItem::new(app, "start", true,  None::<&str>)?;

需要标注泛型的类型,直接写None,会报错

Type annotations needed

with_id方法

函数签名

 pub fn with_id<M, I, T, A>(
    manager: &M,
    id: I,
    text: T,
    enabled: bool,
    accelerator: Option<A>,
  ) -> crate::Result<Self>

 就多了个id参数,比如

let hello_item = MenuItem::with_id(app, "hello", "Hello", true,None::<&str>)?;

 子菜单——SubMenu

Submenu in tauri::menu - Rusthttps://docs.rs/tauri/2.4.0/tauri/menu/struct.Submenu.html这个简单来说,就是放前面的菜单栏,也可以不用子菜单。这里就使用了。

这个也可以使用new方法,也有with_id,或者使用with_items,写法很多种。‘

new方法
ub fn new<M: Manager<R>, S: AsRef<str>>(
    manager: &M,
    text: S,
    enabled: bool,
  ) -> crate::Result<Self>
    let first_submenu = Submenu::new(
        app, // 
        "first",
        true
    )?;
    first_submenu.append(&hello_item)?;
with_id方法
pub fn with_id<M: Manager<R>, I: Into<MenuId>, S: AsRef<str>>(
    manager: &M,
    id: I,
    text: S,
    enabled: bool,
  ) -> crate::Result<Self>
    let first_submenu = Submenu::with_id(
        app,
        "first_submenu",
        "First Submenu",
        true,
    )?.append(
        &hello_item,
    )?;
with_items方法
  pub fn with_items<M: Manager<R>, S: AsRef<str>>(
    manager: &M,
    text: S,
    enabled: bool,
    items: &[&dyn IsMenuItem<R>],
  ) -> crate::Result<Self> 

 这个items的类型 &[&dyn IsMenuItem<R>],

首先&[] ,表示引用切片

dyn是Rust中的关键字,

dyn表示动态分发(dynamic dispatch)的 trait 对象,用于需要存储或操作多种实现同一 trait 的类型

1、在运行时(而非编译时)确定具体类型

2、通过统一接口处理不同的类型

dyn trait

对于&[&dyn IsMenuItem<R>],

 简单的说,首先,是个切片。其次,包含多个实现了IsMenuItem这个trait 的不同具体类型的引用

更明白的说,里面可以写如下的东西

IsMenuItem in tauri::menu - Rusthttps://docs.rs/tauri/2.4.0/tauri/menu/trait.IsMenuItem.html

 因此,代码如下

    let first_submenu = Submenu::with_items(
        app,
        "first_submenu",
        true,
        &[&hello_item, &world_item],
    )?;

无论用那种方法,总之,差不多。

菜单——Menu

Menu in tauri::menu - Rusthttps://docs.rs/tauri/2.4.0/tauri/menu/struct.Menu.html

根上面差不了多少,直接给出代码

    let menu=Menu::with_id_and_items(
        app,
        "menu_id",
        &[&first_submenu]
    )?;

使用了with_id_and_items,既要写id,也要加item。

最终menu.rs的代码如下

use tauri::menu::{Menu, MenuItem, Submenu,IconMenuItem};
use tauri::{AppHandle,  Wry,Result};
use tauri::image::Image;

pub fn create_menu(app: &AppHandle) ->Result<Menu<Wry>> {

    let hello_item = MenuItem::with_id(app, "hello", "Hello", true,None::<&str>)?;
    let world_item = MenuItem::with_id(app, "world", "World", true,None::<&str>)?;
    let icon_item=IconMenuItem::with_id(
        app,
        "icon",
        "Icon",
        true,
        Some(Image::from_path("icons/icon.png")?),
        None::<&str>,
    )?;
    let first_submenu = Submenu::with_items(
        app,
        "first_submenu",
        true,
        &[&hello_item, &world_item,&icon_item],
    )?;
    let menu=Menu::with_id_and_items(
        app,
        "menu_id",
        &[&first_submenu]
    )?;
    Ok(menu)
}

main.rs的关键代码

 .setup(|app| {
            let app_handle = app.handle();
            let menu= menu::create_menu(app_handle)?;
            app.set_menu(menu)?;
            Ok(())
        })

 笔者还使用了IconMenuItem,实际上和前面差不多,只是多了图片。

IconMenuItem in tauri::menu - Rusthttps://docs.rs/tauri/2.4.0/tauri/menu/struct.IconMenuItem.html

cargo run

结果如下

看起来文字显示不完全,笔者也没有解决。

间接创建

感觉类似于工厂模式,先要有给工厂,在工厂里面生产菜单,而这个工厂就是MenuBuilder

use tauri::menu::MenuBuilder

笔者看官网是这么写的。

还有其他工厂。

因此,直接复制了,

use tauri::menu::{Menu, MenuBuilder,SubmenuBuilder,CheckMenuItemBuilder,IconMenuItemBuilder};
use tauri::{AppHandle,  Wry,Result};
use tauri::image::Image;

pub fn create_menu(app: &AppHandle) ->Result<Menu<Wry>> {
    let text_menu = SubmenuBuilder::new(app, "File")
        .text("open", "Open")
        .text("quit", "Quit")
        .build()?;

    let lang_str = "en";
    let check_sub_item_1 = CheckMenuItemBuilder::new("English")
        .id("en")
        .checked(lang_str == "en")
        .build(app)?;

    let check_sub_item_2 = CheckMenuItemBuilder::new("Chinese")
        .id("en")
        .checked(lang_str == "en")
        .enabled(false)
        .build(app)?;

    let icon_image = Image::from_path("icons/icon.png")
        .expect("failed to load icon");

    let icon_item = IconMenuItemBuilder::new("icon")
        .icon(icon_image)
        .build(app)?;

    let check_menus = SubmenuBuilder::new(app, "language")
        .item(&check_sub_item_1)
        .item(&check_sub_item_2)
        .build()?;


    let menu = MenuBuilder::new(app)
        .items(&[&text_menu, &check_menus, &icon_item])
        .build()?;
        
    Ok(menu)
}

在前端创建菜单

感觉在后端写菜单,不是很好看,在前端试试。

下面这个链接是一位大佬的模板

jbolda/personal-tray-app: Looking to create a Tauri app that runs in the background and is accessible through the system tray or a keyboard? Use this template as a way to jump start creating your app.https://github.com/jbolda/personal-tray-app/以后文章中经常使用这个模板。这个模板封装的可以。

项目的关键结构如下

写了这么久,很少写前端。哈哈哈哈

如下是前端menu的参考

菜单 | Tauri - Tauri 框架https://v2.tauri.org.cn/reference/javascript/api/namespacemenu/setup.ts中代码

import { useEffect, useState } from "react";
import { Menu,MenuOptions} from "@tauri-apps/api/menu";

export function useTauri(menuItems: MenuOptions) {
    const [menu, setMenu] = useState<null | Menu>(null);

    useEffect(() => {
        async function init() {
            const initMenu = await Menu.new(menuItems);
            await initMenu.setAsWindowMenu()
            setMenu(initMenu);
        }
        init()
            .then(() => console.log("初始化菜单成功"))
            .catch((error) => console.error("初始化菜单失败:", error));
    }, []);

    return { menu };
}

 context.ts

import { Menu } from "@tauri-apps/api/menu";
import { createContext } from "react";

export const SystemMenuContext = createContext<{
    menu: null | Menu;
}>({
    menu: null,
});

 App.tsx

import {SystemMenuContext} from './context.ts'
import {useTauri} from "./hook/setup.ts";
import {MenuOptions} from "@tauri-apps/api/menu";
import "./App.css";


function App() {
    const menuItems = {
            id: "first",
            items: [
                {
                    id: "first-item",
                    text: "First",
                },
                {
                    id: "second-item",
                    text: "Second",
                    items: [
                        {
                            id: "sub-item-1",
                            text: "Sub Item 1",
                        },
                        {
                            id:'separator',
                            item:"Separator"
                        },
                        {
                            id: "sub-item-2",
                            text: "Sub Item 2",
                        },
                        {
                            id: "icon-item",
                            text: "Icon Item",
                            icon:  "icons/icon.png" ,
                        }
                    ]
                },
                // icon menu item
                {
                    id: "icon-item",
                    text: "Icon Item",
                    icon:  "icons/icon.png" ,
                }
            ]
        } as MenuOptions;

    return (
        <SystemMenuContext.Provider value={useTauri(menuItems)}>
            <header className="App-header">
                <h1>My Tauri App</h1>
            </header>
        </SystemMenuContext.Provider>
    );
}

export default App;

参数是差不多,都有上面id,text之的类,

感觉差不多,。

总结

简单的在前端和后端创建了menu,差不多,只是创建了,还有其他东西,比如action。后面再说。

相关文章:

  • 电脑基础之excel基础操作
  • 网络攻防快速入门笔记pwn | 02 栈溢出题型 | 2.1 ret2text和ret2shellcode
  • 鸿蒙Next-开发版本升级,API升级(例如API12升API16)
  • 前端界面在线excel编辑器 。node编写post接口获取文件流,使用传参替换表格内容展示、前后端一把梭。
  • Django学习笔记
  • 第二章:基础页面实现 - 第一节:登录与注册页面 - 表单与身份验证UI
  • 飞腾派OS(无桌面版本基于Debian11)安装weston桌面及Qt
  • LLM应用层推荐 -- 基于文档的问答tools Web UI 框架 开源向量库 -- 推荐、对比
  • 飞速(FS)HPC无损组网:驱动AI高性能计算网络转型升级
  • Qt笔记----》不同环境程序打包
  • 【docker】将docker容器中的文件复制到宿主机的方法
  • centos线程数查看
  • Typora 小乌龟 git 上传到gitee仓库教程
  • git push失败的解决办法
  • 北斗导航 | THE GNSS AMBIGUITY RATIO-TEST REVISITED: A BETTER WAY OF USING IT【论文要点】
  • linux-core分析-柔性数组越界访问
  • c++中int、float、double类型数据与string类型数据相互转换
  • 一文掌握 Velox orderby 算子的排序算法
  • AWS S3 和 Lambda 使用
  • 【超详细】讲解Ubuntu上如何配置分区方案
  • 黄晨光任中科院空间应用工程与技术中心党委书记、副主任
  • 华为招聘:未与任何第三方开展过任何形式的实习合作
  • AMD:预计美国芯片出口管制将对全年营收造成15亿美元损失
  • 吴清稳市场稳预期发布会十要点:谈平准基金、股市稳定、公募改革和巴菲特
  • 中方对中美就关税谈判的立场发生变化?外交部:中方立场没有任何改变
  • 詹丹|高考语文阅读题设计和答案拟制的一些缺憾