Tauri(Rust+React+TypeScript) から始めるディスクトップアプリ #4[Menuの実装]
はじめに
現在、MonacoEditorに入力した文字列を普通のEditorとして動作するようにしていっています。
今回は、Menuを実装します。
最近のアプリケーションは、Menu実装しているは少数だと思いますが、マウス操作をなるべくしたくないのでMenuを実装して、ショートカット操作をわかりやすくしたいです。
Menu の組み込み
Menuは Crate tauri で実装します。
まず、os_defaultを表示します。
下記の部分を記述しましょう。
+ use tauri::{CustomMenuItem, Menu, MenuItem,Submenu};
fn main() {
~
+ let context = tauri::generate_context!();
+ let menu = Menu::os_default(&context.package_info().name);
~
tauri::Builder::default()
+ .menu(menu)
.invoke_handler(tauri::generate_handler![greet,output])
.run(tauri::generate_context!())
.expect("error while running tauri application");
~
サクッと実行
上記のように表示できれば、ひとまず完了です。
Menuこのメニューは、Defaultで用意されているものですが、このままでは要件を満たしていません。
Menu のカストマイズ
os_defaultはあくまで、サンプルみたいなものです。
オーバライトはできるとは思いますが。。。要件にあった独自メニューを作成しましょう。
独自メニューを下記のようにしたいと思います。
※en表記です。日本語つか多言語化は別途考えています。
File
Project
Project Create
Project Open
Separator
File Open... Ctrl + o
File Save Ctrl + s
File Save As... Ctrl + Sihft + s
Separator
quit Alt + F4
Separator
Exit
Edit
Undo
Redo
Separator
cut
Menu構造体とCustomMenuItem構造体の詳細内容
独自メニューは Menu構造体を作成してTauri実行時に指定します。
tauri::Builder::default()
.menu(menu構造体)
Menu構造体の作成は下記の関数を用いて行います。
- fn add_native_item //Tauriが用意しているもの
- fn add_item //独自定義のもの
- fn add_submenu //サブメニュー作成する場合
fn add_native_item
fn add_native_itemは少し特殊でTauri側で用意しているメニューを追加する関数です。
ショートカットも定義済みなので用意してある場合は使いましょう。
注意点としてnative_itemは、OS毎に異なるので下記の表を参考にしてください。
Name | Windows | mac | lunux | etc |
---|---|---|---|---|
About(String, AboutMetadata) | - | ○ | ○ | metadata is only applied on Linux |
Hide | ○ | ○ | ○ | |
Services | - | ○ | - | |
HideOthers | - | ○ | - | |
ShowAll | - | ○ | - | |
CloseWindow | ○ | ○ | ○ | |
Quit | ○ | ○ | ○ | |
Copy | ○ | ○ | - | |
Cut | ○ | ○ | - | |
Undo | - | ○ | - | |
Redo | - | ○ | - | |
SelectAll | - | ○ | - | |
Paste | ○ | ○ | - | |
EnterFullScreen | - | ○ | - | |
Minimize | ○ | ○ | ○ | |
Zoom | - | ○ | - | |
Separator | ○ | ○ | ○ |
プラットフォーム毎にサポート状況が大きく異なるため留意が必要です。
なんだかんだでMac最高!って事ですね)草
fn add_item
CustomMenu構造体に、fn CustomMenuItemを使ってデータを入れます。
作成した、CustomMenu構造体をfn add_itemを使ってMenu構造体に格納します。
CustomMenuItem の構造体は下記のようになっています。
pub struct CustomMenuItem {
pub id: MenuHash,
pub id_str: MenuId,
pub title: String,
pub keyboard_accelerator: Option<String>,
pub enabled: bool,
pub selected: bool,
#[cfg(target_os = "macos")]
pub native_image: Option<NativeImage>,
}
id: 一意にして選択時に、イベントを拾います。
title: タイトルです。
keyboard_accelerator: ショートカットの表示をします。
enabled: bool false にすると 選択不可となります。
selected: bool true にすると check が付きます。
pub native_image: Option<NativeImage> mac ならIcon表示できそう。。。
例
let file_open = CustomMenuItem::new("fileopen","File Open...").accelerator("Ctrl + N").selected().disabled();
let menu = Menu::new().add_item(file_open));
fn add_submenu
サブメニューを作る場合に使います。
ごちゃごちゃ説明するよりコードを参考にしてください。
let submenu = Submenu::new("File", Menu::new()
.add_submenu(menu_project)
.add_native_item(MenuItem::Separator)
.add_item(file_open)
.add_item(file_save)
.add_item(file_save_as)
.add_native_item(MenuItem::Separator)
.add_native_item(MenuItem::Quit));
サブメニューの中にサブメニューを作成できます。
## Menu構造体
配列の構造体になっています。
Printlnで出来上がった物を見るとわかりやすいので確認してみてください。
サブメニュのサンプルと同じです。初期化後、add_submenu、add_item、add_native_itemにて配列にデータを追加します。簡単に書くと下記のような記述です。
let mut menu = Menu::new();
menu = menu.add_submenu(xxxxxx);
menu = menu.add_item(xxxxx);
menu = menu.add_native_item(xxxx);
サンプルのコード
それではコードです。
fn main() {
//引数の取得
let args: Vec<String> = env::args().collect();
let exefilename = &args[0];
//let path= &args[1];
let path:String = exefilename.replace("D4DataStudio.exe", "");
let logfilename: String = path + "D4DataStudio.log";
//Project Menu
let project_create = CustomMenuItem::new("projectnew", "Project Create",).accelerator("Alt+C");
let project_open = CustomMenuItem::new("projectopen", "Project Open...",).accelerator("Alt+P");
let menu_project = Submenu::new("Project",Menu::new()
.add_item(project_create)
.add_item(project_open)
);
//File menu
let file_open = CustomMenuItem::new("fileopen","File Open...").accelerator("Ctrl + N");
let file_save = CustomMenuItem::new("filesave","File Save",).accelerator("Ctrl + S");
let file_save_as = CustomMenuItem::new("filesaveas","File Save As...",).accelerator("Ctrl + Shift + S");
let file_menu = Submenu::new("File", Menu::new()
.add_submenu(menu_project)
.add_native_item(MenuItem::Separator)
.add_item(file_open)
.add_item(file_save)
.add_item(file_save_as)
.add_native_item(MenuItem::Separator)
.add_native_item(MenuItem::Quit));
//Edit menu
let undo = ::new("undo","Undo").accelerator("Ctrl + Z");
let redo = CustomMenuItem::new("redo","Redo",).accelerator("Ctrl + Y");
let edit_menu = Submenu::new("Edit", Menu::new()
.add_item(undo)
.add_item(redo)
.add_native_item(MenuItem::Separator)
.add_native_item(MenuItem::Cut)
.add_native_item(MenuItem::Copy)
.add_native_item(MenuItem::Paste));
let menu = Menu::new()
.add_submenu(file_menu)
.add_submenu(edit_menu);
//Debug
println!("{:?}",menu);
//ロガーの初期化
logger::init(&logfilename);
logger::output(logger::Loggerkind::Info, "Logging Initial complete!");
//Tauri 実行
tauri::Builder::default()
.menu(menu)
.on_menu_event(|event| {
match event.menu_item_id() {
"fileopen" => {
println!("File_Open :: {:?}",event.menu_item_id());
}
"filesave" => {
println!("FileSave :: {:?}",event.menu_item_id());
}
_ => {
println!("未実装 :: {:?}",event.menu_item_id());
}
}
})
.invoke_handler(tauri::generate_handler![greet,output])
.run(tauri::generate_context!())
.expect("error while running tauri application");
on_menu_event にて、eventをフックしています。add_native_itemで定義しているものは、検知できないので注意してください。
また、CustomMenuItem構造体で定義したものは、ショートカットキーが実装できていません。
また、Alt + F にて、Fileメニューを開くようにしたいですが、現状実現できていません。
実行結果
npm run tauri dev
お疲れさまでした。
あとがき
次回はショートカット実装を頑張りたい。
Discussion