Tauri 菜单、系统托盘和进程之前的通信

1,894 阅读3分钟

上一篇我们使用tauri创建的应用的基础操作,这一篇我们主要讲一下tauri的菜单,系统托盘和进程之间的通信等操作

创建体积更小、运行更快、更加安全的跨平台桌面应用——初步了解Tauri

菜单

tauri的菜单可以使用系统的菜单也可以自定义菜单

mac系统支持的比较好有很多,相比windows和Linux支持就相对少了一些

Windows:
	File
	CloseWindow
	Quit
	Edit
	Cut
	Copy
	Paste
	Window
	Minimize
	CloseWindow
Linux:
	File
	CloseWindow
	Quit
	Window
	Minimize
	CloseWindow
macOS:
	App
	About
	Separator
	Services
	Separator
	Hide
	HideOthers
	ShowAll
	Separator
	Quit
	File
	CloseWindow
	Edit
	Undo
	Redo
	Separator
	Cut
	Copy
	Paste
	SelectAll
	View
	EnterFullScreen
	Window
	Minimize
	Zoom
	Separator
	CloseWindow

系统菜单

系统菜单 通过add_native_item方法添加系统菜单,例如添加复制菜单

Menu::new().add_native_item(MenuItem::Copy)

自定义菜单

通过add_native_item方法添加系统菜单,例如添加退出登录的自定义菜单

Menu::new().add_item(CustomMenuItem::new("logout".to_string(), "退出登录"))

通过accelerator方法给自定义菜单添加快捷键 例如添加重新加载的自定义菜单 并通过Cmd+R的快捷键触发

Menu::new()
  .add_item(
		CustomMenuItem::new("reload".to_string(), "重新加载")
		  .accelerator("CmdOrCtrl+R")
			.into(),
  )

自定义菜单需要添加监听自定义菜单事件来执行相关操作

tauri::Builder::default()
	// 添加菜单
	.menu(menus)
	// 监听自定义菜单事件
	.on_menu_event(|event| match event.menu_item_id() {
		// 退出app
		"quit" => {
			std::process::exit(0);
		}
		// 关闭窗口
		"close" => {
			event.window().close().unwrap();
		}
		// 向客户端广播刷新事件
		"reload" => event
			.window()
			.app_handle()
			.emit_all("event-reload", Payload {})
			.unwrap(),

系统托盘

系统托盘的使用和菜单比较类似,也是需要添加相关操作和监听自定义菜单事件来执行相关操作

    let quit = CustomMenuItem::new("quit".to_string(), "退出");
    let close = CustomMenuItem::new("close".to_string(), "关闭窗口");
    let hide = CustomMenuItem::new("hide".to_string(), "隐藏窗口");
    let tray_menu = SystemTrayMenu::new()
        .add_item(hide)
        .add_native_item(SystemTrayMenuItem::Separator)
        .add_item(close)
        .add_native_item(SystemTrayMenuItem::Separator)
        .add_item(quit);

    tauri::Builder::default()
        .system_tray(SystemTray::new().with_menu(tray_menu))

进程间通信

rust向js广播事件 通过appHandle的emit_all方法实现的

"reload" => event
	.window()
	.app_handle()
	.emit_all("event-reload", Payload {})
	.unwrap(),

js注册事件接受广播

// 导入 listen 方法 监听事件
import { listen } from '@tauri-apps/api/event'
listen('event-reload', () => {
  window.location.reload()
})

js向rust广播事件

// 导入 invoke 方法
import { invoke } from '@tauri-apps/api/tauri'
 
// 添加监听函数,监听 DOM 内容加载完成事件
document.addEventListener('DOMContentLoaded', () => {
  // DOM 内容加载完成之后,通过 invoke 调用 在 Rust 中已经注册的命令
  invoke('close_splashscreen')
})

rust注册事件接受广播

 tauri::Builder::default()
   // 注册命令
   .invoke_handler(tauri::generate_handler![close_splashscreen])

完整代码

src-tauri\main.rs 完整代码如下

use tauri::{
  CustomMenuItem, Manager, Menu, MenuItem, Submenu, SystemTray, SystemTrayEvent, SystemTrayMenu,
  SystemTrayMenuItem,
};

#[derive(Clone, serde::Serialize)]
struct Payload {}

fn main() {
  let submenu_app = Submenu::new(
    "Turbo's 笔记",
    Menu::new()
      .add_item(CustomMenuItem::new("about".to_string(), "检查版本"))
      .add_native_item(MenuItem::Separator)
      .add_item(
        CustomMenuItem::new("hide".to_string(), "隐藏 Turbo's 笔记")
          .accelerator("CmdOrCtrl+H")
          .into(),
      )
      .add_item(
        CustomMenuItem::new("show".to_string(), "显示 Turbo's 笔记")
          .accelerator("CmdOrCtrl+S")
          .into(),
      )
      .add_native_item(MenuItem::Separator)
      .add_item(
        CustomMenuItem::new("quit".to_string(), "退出")
          .accelerator("CmdOrCtrl+Q")
          .into(),
      ),
  );
  let submenu_edit = Submenu::new(
    "编辑",
    Menu::new()
      .add_native_item(MenuItem::Redo)
      .add_native_item(MenuItem::Undo)
      .add_native_item(MenuItem::Separator)
      .add_native_item(MenuItem::Cut)
      .add_native_item(MenuItem::Copy)
      .add_native_item(MenuItem::Paste),
  );
  let submenu_view = Submenu::new(
    "视图",
    Menu::new()
      .add_item(
        CustomMenuItem::new("reload".to_string(), "重新加载")
          .accelerator("CmdOrCtrl+R")
          .into(),
      )
      .add_item(
        CustomMenuItem::new("logout".to_string(), "退出登录")
          .accelerator("Alt+CmdOrCtrl+Q")
          .into(),
      ),
  );
  let menus = Menu::new()
    .add_submenu(submenu_app)
    .add_submenu(submenu_edit)
    .add_submenu(submenu_view);

  let quit = CustomMenuItem::new("quit".to_string(), "退出");
  let close = CustomMenuItem::new("close".to_string(), "关闭窗口");
  let hide = CustomMenuItem::new("hide".to_string(), "隐藏窗口");
  let tray_menu = SystemTrayMenu::new()
    .add_item(hide)
    .add_native_item(SystemTrayMenuItem::Separator)
    .add_item(close)
    .add_native_item(SystemTrayMenuItem::Separator)
    .add_item(quit);

  tauri::Builder::default()
    .system_tray(SystemTray::new().with_menu(tray_menu))
    .on_system_tray_event(|app, event| menu_handle(app, event))
    // 添加菜单
    .menu(menus)
    // 监听自定义菜单事件
    .on_menu_event(|event| match event.menu_item_id() {
      "about" => event
        .window()
        .app_handle()
        .emit_all("event-about", Payload {})
        .unwrap(),
      "quit" => {
        std::process::exit(0);
      }
      "close" => {
        event.window().close().unwrap();
      }
      "hide" => {
        event.window().hide().unwrap();
      }
      "show" => {
        event.window().show().unwrap();
      }
      "logout" => event
        .window()
        .app_handle()
        .emit_all("event-logout", Payload {})
        .unwrap(),
      "reload" => event
        .window()
        .app_handle()
        .emit_all("event-reload", Payload {})
        .unwrap(),
      _ => {}
    })
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}

fn menu_handle(app_handle: &tauri::AppHandle, event: SystemTrayEvent) {
  match event {
    SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
      "quit" => {
        std::process::exit(0);
      }
      "close" => {
        let window = app_handle.get_window("main").unwrap();
        window.close().unwrap();
      }
      "hide" => {
        let item_handle = app_handle.tray_handle().get_item(&id);
        let window = app_handle.get_window("main").unwrap();
        if window.is_visible().unwrap() {
          window.hide().unwrap();
          item_handle.set_title("显示窗口").unwrap();
        } else {
          window.show().unwrap();
          item_handle.set_title("隐藏窗口").unwrap();
        }
      }
      _ => {}
    },
    _ => {}
  }
}