跳到主要内容

系统托盘

系统托盘(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();
}

最佳实践

  1. 提供退出选项:托盘菜单应始终包含退出选项
  2. 处理关闭按钮:默认将关闭按钮行为改为隐藏到托盘
  3. 单击显示/隐藏:左键单击托盘图标切换窗口显示状态
  4. 状态同步:菜单项状态应与实际窗口状态同步

下一步