iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
Rust

用 Tauri 打造你的應用程式系列 第 14

[Day 14] Menu 選單

  • 分享至 

  • xImage
  •  

在前面的章節中,我們深入探討了如何設計和管理應用程式的視窗系統,從單一視窗的基礎配置到多視窗間的動態管理。然而,一個完整的桌面應用程式體驗不僅僅在於視窗本身,更在於如何讓使用者能夠直觀且高效地操作這些視窗。

應用程式選單正是連接使用者與視窗功能的重要橋樑。一個設計良好的選單系統能夠統一管理各個視窗的操作(如新增、切換、關閉),並為使用者提供直觀且有組織的功能存取方式。今天,我們將學習如何在 Tauri 中建立專業的選單系統,讓我們的多視窗應用程式擁有更完整的使用者體驗。

我覺得 Menu 可以算是視窗的一部分,所以在 Roadmap 上就沒有再另外畫了。

應用程式選單的重要性

應用程式選單是桌面軟體的標誌性特徵之一。它為使用者提供了一個熟悉且有組織的方式來存取應用程式的各種功能。好的選單設計能夠引導使用者發現功能、提高工作效率,並且符合不同作業系統的設計規範。

對於開發者而言,選單系統也是組織應用程式功能的有效方式。透過邏輯性的分組和層次結構,我們可以將複雜的功能以直觀的方式呈現給使用者,同時保持介面的簡潔性。

建立應用程式選單

在 Tauri 中,我們可以在 Rust 後端或 JS 前端建立選單結構,這邊就用 Rust 作為範例:

// lib.rs
use tauri::{Builder, AppHandle, Manager, App};
use tauri::menu::{MenuBuilder, SubmenuBuilder, Menu};

fn create_menu(app: &App) -> tauri::Result<Menu<tauri::Wry>> {
    // 建立 File submenu
    let file_submenu = SubmenuBuilder::new(app, "File")
        .text("open", "Open")
        .text("close", "Close")
        .build()?;

    // 建立 Help submenu
    let help_submenu = SubmenuBuilder::new(app, "Help")
        .text("info", "About")
        .build()?;

    // 建立主選單
    let menu = MenuBuilder::new(app)
        .item(&file_submenu)
        .item(&help_submenu)
        .build()?;

    Ok(menu)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    Builder::default()
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet])
        .setup(|app| {
            // 建立並設定選單
            let menu = create_menu(app)?;
            app.set_menu(menu)?;

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

綁定事件

上面的程式碼只有設定 menu 選單而已,接下來還需要設定 menu event:

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    Builder::default()
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet])
        .setup(|app| {
            // 建立並設定選單
            let menu = create_menu(app)?;
            app.set_menu(menu)?;

+           // 設定選單事件處理器
+           setup_menu_handlers(app);

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
fn show_version_info(app_handle: &AppHandle) {
    let version = app_handle.package_info().version.to_string();
    let app_name = &app_handle.package_info().name;
    
    println!("應用程式版本資訊: {} v{}", app_name, version);
    
    // 嘗試透過前端顯示版本資訊
    if let Some(window) = app_handle.get_webview_window("main") {
        let _ = window.eval(&format!(
            "alert('應用程式版本資訊\\n{} v{}');", 
            app_name, version
        ));
    }
}

fn setup_menu_handlers(app: &App) {
    app.on_menu_event(move |app_handle: &tauri::AppHandle, event| {
        println!("menu event: {:?}", event.id());

        match event.id().0.as_str() {
            "open" => {
                println!("open event");
                // 這裡可以加入開啟檔案的邏輯
            }
            "close" => {
                println!("close event");
                // 這裡可以加入關閉應用程式的邏輯
                let _ = app_handle.exit(0);
            }
            "info" => {
                println!("info event - showing version");
                show_version_info(app_handle);
            }
            _ => {
                println!("unexpected menu event");
            }
        }
    });
}

設定完之後,之後只要點擊 Help 裡的 About,就會呼叫 show_version_info() 顯示版本資訊。

內建的 Menu item

在 Tauri 中,有把一些常見功能先建立好了,讓大家不必重複造輪子更快速地進行功能開發,詳細的設定可以參考文件

use tauri::menu::{MenuBuilder, PredefinedMenuItem};

fn create_predefined_menu(app: &tauri::App) -> tauri::Result<tauri::menu::Menu<tauri::Wry>> {
    let menu = MenuBuilder::new(app)
        .copy()
        .separator()
        .undo()
        .redo()
        .cut()
        .paste()
        .select_all()
        .item(&PredefinedMenuItem::copy(app, Some("Copy with Custom Text"))?)
        .build()?;
    
    Ok(menu)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .setup(|app| {
            let menu = create_predefined_menu(app)?;
            app.set_menu(menu)?;
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

設計原則與最佳實踐

在設計選單結構時,應該遵循作業系統的慣例。Windows 和 macOS 在選單佈局上有不同的傳統,例如 macOS 的「關於」項目通常在應用程式選單中,而 Windows 則放在說明選單裡。

選單項目的文字應該清楚描述其功能,並在適當時提供快捷鍵提示。這不僅幫助使用者學習快捷鍵,也讓選單看起來更加專業。快捷鍵的選擇也要謹慎考慮,避免與系統或其他常用應用程式的快捷鍵衝突。

快捷鍵的設定之後有機會再討論,這篇文章已經有點太長了...

有興趣的人可以先去看一下 Global Shortcut 這個 Plugin

小結

透過這篇文章,我們學會了如何為 Tauri 應用程式建立完整的選單系統:

  1. 原生選單建立:使用 MenuBuilderSubmenuBuilder 創建符合系統規範的選單結構
  2. 事件處理機制:透過 on_menu_event 來回應使用者的選單操作
  3. 視窗整合:選單操作與我們前面學習的視窗管理功能完美結合

結合前面章節學習的視窗管理技巧,我們現在可以建構出具備專業選單系統的多視窗桌面應用程式。使用者能透過選單直觀地管理各個視窗,大大提升了應用程式的易用性和專業度。

下一篇文章,我們將進一步探討 System Tray 的實作,讓應用程式能在系統背景中持續運行並提供快速存取功能。


上一篇
[Day 13] 視窗管理 (二)
系列文
用 Tauri 打造你的應用程式14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言