Tauri 应用篇 - 系统托盘

基本配置

编辑 src-tauri/tauri.conf.json
文件

iconAsTemplate
是一个布尔值,用于确定图像是否表示 macOS 上的模板图像[1](为 true
时图像应仅包含黑色和清晰的颜色,为 false
时图片显示原色)。在 Linux 上,则需要安装软件包对其进行支持,从官方文档了解 Linux 设置[2]。

{
  "tauri": {
    "systemTray": {
      "iconPath": "icons/icon.png", // 托盘图标,默认根路径为 `src-tauri/`
      "iconAsTemplate": true
    }
  }
}

编辑 src-tauri/src/main.rs
文件

#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

fn main() {
    let context = tauri::generate_context!();
    tauri::Builder::default()
        .system_tray(tauri::SystemTray::default()) // ✅ 将 `tauri.conf.json` 上配置的图标添加到系统托盘
        .run(context)
        .expect("error while running OhMyBox application");
}

注意:点击托盘图标无响应,是因为并未对其添加菜单和事件。

托盘菜单 & 事件

菜单 API

  • SystemTrayMenu
    - 创建一个新菜单

  • SystemTraySubmenu
    - 使用给定的标题和菜单项创建一个新的子菜单

  • CustomMenuItem
    - 自定义菜单项,与 Menu
    中的 CustomMenuItem
    用法一致

  • SystemTrayMenuItem
    - 原生菜单项,目前仅支持菜单分割符 SystemTrayMenuItem::Separator

注意:虽然应用菜单和托盘菜单都是菜单,但除 CustomMenuItem
与 Menu 共用外,其他 API 不可以混用。

托盘菜单项

SystemTrayMenu::new()

  • add_item
    - 将自定义菜单项添加到系统托盘菜单

    use tauri::{SystemTrayMenu, CustomMenuItem};
    
    SystemTrayMenu::new()
      .add_item(CustomMenuItem::new("quit".to_string(), "Quit"))
      .add_item(CustomMenuItem::new("close".to_string(), "Close"));
    
    
  • add_native_item
    - 将原生菜单项添加到系统托盘菜单

    use tauri::{SystemTrayMenu, SystemTrayMenuItem, CustomMenuItem};
    
    SystemTrayMenu::new()
      .add_item(CustomMenuItem::new("quit".to_string(), "Quit"))
      .add_native_item(SystemTrayMenuItem::Separator) // ✅ 菜单分割线
      .add_item(CustomMenuItem::new("close".to_string(), "Close"));
    
    
  • add_submenu
    - 添加一个带有子菜单的条目

    use tauri::{SystemTrayMenu, SystemTraySubmenu, SystemTrayMenuItem, CustomMenuItem};
    
    SystemTrayMenu::new()
      .add_submenu(SystemTraySubmenu::new(
        "File",
        SystemTrayMenu::new()
          .add_item(CustomMenuItem::new("new_file".to_string(), "New File"))
          .add_item(CustomMenuItem::new("edit_file".to_string(), "Edit File")),
      ))
      .add_native_item(SystemTrayMenuItem::Separator)
      .add_item(CustomMenuItem::new("hide".to_string(), "Hide"))
      .add_item(CustomMenuItem::new("show".to_string(), "Show"))
      .add_native_item(SystemTrayMenuItem::Separator)
      .add_item(CustomMenuItem::new("quit".to_string(), "Quit"));
    

 

创建托盘菜单

新建 src-tauri/src/tray.rs
文件

use tauri::{SystemTray, CustomMenuItem, SystemTrayMenu, SystemTrayMenuItem, SystemTraySubmenu};

// 托盘菜单
pub fn menu() -> SystemTray {
    let tray_menu = SystemTrayMenu::new()
        .add_submenu(SystemTraySubmenu::new( // 子菜单
            "File", // 子菜单名称
            SystemTrayMenu::new()
                .add_item(CustomMenuItem::new("new_file".to_string(), "New File")) // 子菜单项(新增)
                .add_item(CustomMenuItem::new("edit_file".to_string(), "Edit File")), // 子菜单项(编辑)
        ))
        .add_native_item(SystemTrayMenuItem::Separator) // 分割线
        .add_item(CustomMenuItem::new("hide".to_string(), "Hide")) // 隐藏应用窗口
        .add_item(CustomMenuItem::new("show".to_string(), "Show")) // 显示应用窗口
        .add_native_item(SystemTrayMenuItem::Separator) // 分割线
        .add_item(CustomMenuItem::new("quit".to_string(), "Quit")); // 退出

    // 设置在右键单击系统托盘时显示菜单
    SystemTray::new().with_menu(tray_menu)
}

// 菜单事件
pub fn handler(app: &AppHandle, event: SystemTrayEvent) {
    // 获取应用窗口
    let window = app.get_window("main").unwrap();
    let parent_window = Some(&window);
    // 匹配点击事件
    match event {
        // 左键点击
        SystemTrayEvent::LeftClick {
            position: _,
            size: _,
            ..
        } => {
            println!("system tray received a left click");
        }
        // 右键点击
        SystemTrayEvent::RightClick {
            position: _,
            size: _,
            ..
        } => {
            println!("system tray received a right click");
        }
        // 双击,macOS / Linux 不支持
        SystemTrayEvent::DoubleClick {
            position: _,
            size: _,
            ..
        } => {
            println!("system tray received a double click");
        }
        // 根据菜单 id 进行事件匹配
        SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
            "edit_file" => {
                message(parent_window, "Eidt File", "TODO");
            }
            "new_file" => {
                message(parent_window, "New File", "TODO");
            }
            "quit" => {
                std::process::exit(0);
            }
            "show" => {
                window.show().unwrap();
            }
            "hide" => {
                window.hide().unwrap();
            }
            _ => {}
        },
        _ => {}
    }
}

编辑 src-tauri/src/main.rs
文件

#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

mod tray;

fn main() {
    let context = tauri::generate_context!();
    tauri::Builder::default()
        .menu(tauri::Menu::os_default(&context.package_info().name))
        .system_tray(tray::menu())  // ✅ 将 `tauri.conf.json` 上配置的图标添加到系统托盘
        .on_system_tray_event(tray::handler) // ✅ 注册系统托盘事件处理程序
        .run(context)
        .expect("error while running OhMyBox application");
}

注意:只创建菜单项,而不添加事件处理,点击菜单依然会无响应。

更新系统托盘

AppHandle
上有一个 tray_handle
方法,用于返回系统托盘的句柄,可以用来更新托盘图标和上下文菜单项。

更新 src-tauri/src/tray.rs
文件

use tauri::{AppHandle, CustomMenuItem, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, SystemTraySubmenu};

// 托盘菜单
pub fn menu() -> SystemTray {
    let quit = CustomMenuItem::new("quit".to_string(), "Quit");
    let show = CustomMenuItem::new("show".to_string(), "Show");
    let hide = CustomMenuItem::new("hide".to_string(), "Hide");
    let change_ico = CustomMenuItem::new("change_ico".to_string(), "Change Icon");
    let tray_menu = SystemTrayMenu::new()
        .add_submenu(SystemTraySubmenu::new(
            "Language", // 语言菜单
            SystemTrayMenu::new()
                .add_item(CustomMenuItem::new("lang_english".to_string(), "English"))
                .add_item(CustomMenuItem::new("lang_zh_CN".to_string(), "简体中文"))
                .add_item(CustomMenuItem::new("lang_zh_HK".to_string(), "繁体中文")),
        ))
        .add_native_item(SystemTrayMenuItem::Separator) // 分割线
        .add_item(change_ico)
        .add_native_item(SystemTrayMenuItem::Separator)
        .add_item(hide)
        .add_item(show)
        .add_native_item(SystemTrayMenuItem::Separator)
        .add_item(quit);

    SystemTray::new().with_menu(tray_menu)
}

// 托盘事件
pub fn handler(app: &AppHandle, event: SystemTrayEvent) {
    match event {
        SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
            "change_ico" => { // 更新托盘图标
                app.tray_handle()
                    .set_icon(tauri::Icon::Raw(
                        include_bytes!("../icons/toolbox.png").to_vec(),
                    ))
                    .unwrap();
            }
            lang if lang.contains("lang_") => { // 选择语言,匹配 id 前缀包含 `lang_` 的事件
                Lang::new(
                    app,
                    id, // 点击菜单的 id
                    vec![
                        Lang {
                            name: "English",
                            id: "lang_english",
                        },
                        Lang {
                            name: "繁体中文",
                            id: "lang_zh_HK",
                        },
                        Lang {
                            name: "简体中文",
                            id: "lang_zh_CN",
                        },
                    ],
                );
            }
            _ => {}
        },
        _ => {}
    }
}

struct Lang<'a> {
    name: &'a str,
    id: &'a str,
}

impl Lang<'static> {
    fn new(app: &AppHandle, id: String, langs: Vec<Lang>) {
        // 获取点击的菜单项的句柄
        // 注意 `tray_handle` 可以在任何地方调用,只需在 setup 钩子上使用 `app.handle()` 获取 `AppHandle` 实例,将其移动到另一个函数或线程
        langs.iter().for_each(|lang| {
            let handle = app.tray_handle().get_item(lang.id);
            if lang.id.to_string() == id.as_str() {
                // 设置菜单名称
                handle.set_title(format!("🥳 {}", lang.name)).unwrap();
                // 还可以使用 `set_selected`、`set_enabled` 和 `set_native_image`(仅限 macOS)
                handle.set_selected(true).unwrap();
            } else {
                handle.set_title(lang.name).unwrap();
                handle.set_selected(false).unwrap();
            }
        });
    }
}

编辑 src-tauri/Cargo.toml
文件,tauri 新增 icon-png
,直接使用 tauri::Icon
API 设置托盘图标会报错,具体原因可以查看此 issues Path variant of tauri::Icon cannot be found, despite being a documented variant[3]

[dependencies]
tauri = { version = "1.0.5", features = ["api-all", "icon-png", "macos-private-api", "system-tray"] }

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值