系统托盘
系统托盘(System Tray)是桌面应用常驻后台的重要方式。Tauri 提供了完整的系统托盘 API。
基础配置
启用系统托盘
在 tauri.conf.json 中配置:
{
"app": {
"withGlobalTauri": true,
"windows": []
},
"bundle": {
"icon": ["icons/32x32.png", "icons/128x128.png"]
}
}
创建托盘图标
Rust 代码:
use tauri::{Manager, TrayIconBuilder};
pub fn run() {
tauri::Builder::default()
.setup(|app| {
let tray = TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.tooltip("我的应用")
.build(app)
.unwrap();
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
托盘菜单
创建菜单
use tauri::menu::{Menu, MenuItem, PredefinedMenuItem};
pub fn run() {
tauri::Builder::default()
.setup(|app| {
// 创建菜单项
let show_i = MenuItem::with_id(app, "show", "显示", true, None::<&str>)?;
let hide_i = MenuItem::with_id(app, "hide", "隐藏", true, None::<&str>)?;
let quit_i = MenuItem::with_id(app, "quit", "退出", true, None::<&str>)?;
// 创建菜单
let menu = Menu::with_items(app, &[
&show_i,
&hide_i,
&PredefinedMenuItem::separator(app)?,
&quit_i,
])?;
// 创建托盘
let _tray = TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.menu(&menu)
.on_menu_event(|app, event| {
match event.id.as_ref() {
"show" => {
if let Some(window) = app.get_webview_window("main") {
window.show().unwrap();
window.set_focus().unwrap();
}
}
"hide" => {
if let Some(window) = app.get_webview_window("main") {
window.hide().unwrap();
}
}
"quit" => {
app.exit(0);
}
_ => {}
}
})
.build(app)?;
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
菜单项类型
| 类型 | 说明 |
|---|---|
MenuItem | 普通菜单项 |
PredefinedMenuItem::separator | 分隔线 |
PredefinedMenuItem::copy | 复制 |
PredefinedMenuItem::cut | 剪切 |
PredefinedMenuItem::paste | 粘贴 |
PredefinedMenuItem::select_all | 全选 |
CheckMenuItem | 带复选框的菜单项 |
IconMenuItem | 带图标的菜单项 |
动态更新菜单
use tauri::menu::MenuItem;
// 更新菜单项文本
let item = app.menu().unwrap().get("item_id").unwrap();
item.set_text("新文本").unwrap();
// 更新菜单项状态
let check_item = app.menu().unwrap().get("check_id").unwrap();
check_item.set_checked(true).unwrap();
// 启用/禁用菜单项
item.set_enabled(false).unwrap();
托盘事件
点击托盘图标
let _tray = TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.on_tray_icon_event(|tray, event| {
match event {
tauri::tray::TrayIconEvent::Click {
id: _,
position,
rect: _,
button,
button_state
} => {
if button == tauri::tray::MouseButton::Left {
// 左键点击 - 显示/隐藏窗口
let app = tray.app_handle();
if let Some(window) = app.get_webview_window("main") {
if window.is_visible().unwrap() {
window.hide().unwrap();
} else {
window.show().unwrap();
window.set_focus().unwrap();
}
}
}
}
_ => {}
}
})
.build(app)?;
鼠标事件类型
| 事件 | 说明 |
|---|---|
Click | 鼠标点击 |
DoubleClick | 鼠标双击 |
RightClick | 右键点击 |
Enter | 鼠标进入 |
Move | 鼠标移动 |
Leave | 鼠标离开 |
实战示例
完整的托盘实现
use tauri::{
menu::{Menu, MenuItem, PredefinedMenuItem},
Manager, TrayIconBuilder,
};
pub fn run() {
tauri::Builder::default()
.setup(|app| {
let menu = Menu::with_items(app, &[
&MenuItem::with_id(app, "show", "显示主窗口", true, None::<&str>)?,
&MenuItem::with_id(app, "hide", "隐藏到托盘", true, None::<&str>)?,
&PredefinedMenuItem::separator(app)?,
&MenuItem::with_id(app, "settings", "设置", true, None::<&str>)?,
&PredefinedMenuItem::separator(app)?,
&MenuItem::with_id(app, "quit", "退出", true, None::<&str>)?,
])?;
let _tray = TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.tooltip("我的应用")
.menu(&menu)
.on_menu_event(|app, event| {
match event.id.as_ref() {
"show" => show_main_window(app),
"hide" => hide_main_window(app),
"settings" => open_settings(app),
"quit" => app.exit(0),
_ => {}
}
})
.on_tray_icon_event(|tray, event| {
if let tauri::tray::TrayIconEvent::Click {
button: tauri::tray::MouseButton::Left,
..
} = event {
let app = tray.app_handle();
toggle_window(app);
}
})
.build(app)?;
Ok(())
})
.on_window_event(|window, event| {
match event {
tauri::WindowEvent::CloseRequested { api, .. } => {
// 点击关闭按钮时最小化到托盘
window.hide().unwrap();
api.prevent_close();
}
_ => {}
}
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
fn show_main_window(app: &tauri::AppHandle) {
if let Some(window) = app.get_webview_window("main") {
window.show().unwrap();
window.set_focus().unwrap();
}
}
fn hide_main_window(app: &tauri::AppHandle) {
if let Some(window) = app.get_webview_window("main") {
window.hide().unwrap();
}
}
fn toggle_window(app: &tauri::AppHandle) {
if let Some(window) = app.get_webview_window("main") {
if window.is_visible().unwrap() {
window.hide().unwrap();
} else {
window.show().unwrap();
window.set_focus().unwrap();
}
}
}
fn open_settings(app: &tauri::AppHandle) {
// 打开设置窗口
if let Some(window) = app.get_webview_window("settings") {
window.show().unwrap();
window.set_focus().unwrap();
} else {
// 创建设置窗口
tauri::WebviewWindowBuilder::new(
app,
"settings",
tauri::WebviewUrl::App("settings.html".into())
)
.title("设置")
.inner_size(600, 400)
.center()
.build()
.unwrap();
}
}
显示托盘通知
use tauri::notification::Notification;
#[tauri::command]
fn show_notification(app: tauri::AppHandle, title: String, body: String) {
Notification::new(&app.config().tauri.bundle.identifier)
.title(title)
.body(body)
.icon("icons/icon.png")
.show()
.unwrap();
}
最佳实践
- 提供退出选项:托盘菜单应始终包含退出选项
- 处理关闭按钮:默认将关闭按钮行为改为隐藏到托盘
- 单击显示/隐藏:左键单击托盘图标切换窗口显示状态
- 状态同步:菜单项状态应与实际窗口状态同步