基本配置
编辑 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"] }