MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Tauriの基礎 - ウインドウ管理のソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Tauriの基礎 - ウインドウ管理
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == Tauriのウインドウ管理機能は、デスクトップアプリケーションにおけるウインドウの作成、操作、イベント処理を包括的にサポートする。<br> 単一ウインドウのアプリケーションから複数ウインドウを連携させるマルチウインドウアプリケーションまで、柔軟なウインドウアーキテクチャを構築できる。<br> <br> Tauri v2では、<code>WebviewWindow</code> APIが中心となり、RustバックエンドとJavaScript フロントエンドの両方からウインドウ操作が可能である。<br> <br> 設定ファイル (<code>tauri.conf.json</code>) による宣言的な初期設定と、プログラムによる動的なウインドウ作成の2つのアプローチを提供する。<br> <br> ウインドウのサイズ変更、最小化、最大化、閉じる等の基本操作に加え、ウインドウ間のデータ共有、イベント通知、状態の永続化 (window-stateプラグイン) 等もサポートする。<br> <br> クロスプラットフォーム対応を考慮した設計により、Windows、MacOS、Linuxで一貫した動作を実現する。<br> <br><br> == ウインドウ管理の基本概念 == ==== WebviewWindow アーキテクチャ ==== Tauri v2におけるウインドウ管理の中核は <code>WebviewWindow</code> である。<br> <br> <center> {| class="wikitable" |+ ウインドウ関連の主要コンポーネント ! コンポーネント !! 説明 |- | WebviewWindow || WebViewコンテンツを表示するウインドウ<br>HTML/CSS/JavaScriptでUIを構築 |- | WebviewWindowBuilder || プログラムによるウインドウ作成用ビルダー<br>プロパティをチェーンで設定 |- | AppHandle || アプリケーション全体へのアクセス<br>ウインドウの取得・作成に使用 |} </center> <br> ==== ウインドウの識別子 ==== 各ウインドウは一意のラベル (label) で識別される。<br> <br> <syntaxhighlight lang="rust"> // ウインドウラベルの例 "main" // メインウインドウ "settings" // 設定ウインドウ "about" // バージョン情報 "dialog" // ダイアログウインドウ </syntaxhighlight> <br> ==== ウインドウのライフサイクル ==== <center> {| class="wikitable" |+ ウインドウライフサイクル |- ! フェーズ !! 説明 !! イベント |- | 作成 || WebviewWindowBuilderで作成 || Created |- | 表示 || <code>visible=true</code> で表示 || Shown |- | フォーカス || ユーザが操作開始 || Focused |- | 操作中 || ユーザがUIを操作 || - |- | 非フォーカス || 別ウインドウにフォーカス移動 || Blurred |- | 最小化 || タスクバーに格納 || Minimized |- | 復元 || 最小化から復元 || Restored |- | 閉じる || ユーザまたはプログラムで閉じる || CloseRequested |} </center><br> <br><br> == tauri.conf.jsonでのウインドウ初期設定 == ==== 基本的な設定 ==== <u>tauri.conf.json</u> ファイルの <code>app.windows</code> 配列でウインドウを定義する。<br> <br> <syntaxhighlight lang="json"> { "productName": "my-tauri-app", "version": "1.0.0", "app": { "windows": [ { "label": "main", "title": "My Application", "width": 1024, "height": 768, "resizable": true, "fullscreen": false, "focus": true } ] } } </syntaxhighlight> <br> ==== 設定プロパティ一覧 ==== <center> {| class="wikitable" |+ ウインドウ設定プロパティ |- ! プロパティ !! 型 !! 説明 !! デフォルト値 |- | label || string || ウインドウの一意識別子 || "main" |- | title || string || ウインドウタイトル || アプリ名 |- | url || string || 初期URL || "/" |- | width || number || 幅 (ピクセル) || 800 |- | height || number || 高さ (ピクセル) || 600 |- | minWidth || number || 最小幅 || - |- | minHeight || number || 最小高さ || - |- | maxWidth || number || 最大幅 || - |- | maxHeight || number || 最大高さ || - |- | resizable || boolean || リサイズ可能か || true |- | maximizable || boolean || 最大化可能か || true |- | minimizable || boolean || 最小化可能か || true |- | closable || boolean || 閉じる可能か || true |- | fullscreen || boolean || フルスクリーン || false |- | visible || boolean || 起動時に表示 || true |- | focus || boolean || 起動時にフォーカス || true |- | transparent || boolean || 透明背景 || false |- | decorations || boolean || タイトルバー表示 || true |- | alwaysOnTop || boolean || 常に最前面 || false |- | center || boolean || 画面中央に配置 || false |- | x || number || X座標 || - |- | y || number || Y座標 || - |} </center><br> <br> ==== マルチウインドウ設定 ==== 複数のウインドウを定義する例を示す。<br> <br> <syntaxhighlight lang="json"> { "app": { "windows": [ { "label": "main", "title": "Main Window", "width": 1200, "height": 800, "center": true }, { "label": "settings", "title": "Settings", "url": "/settings", "width": 600, "height": 500, "visible": false, "resizable": false }, { "label": "about", "title": "About", "url": "/about", "width": 400, "height": 300, "resizable": false, "maximizable": false, "minimizable": false } ] } } </syntaxhighlight> <br> ==== スプラッシュスクリーン設定 ==== アプリケーション起動時にスプラッシュスクリーンを表示して、初期化完了後にメインウインドウを表示する設定。<br> <br> <syntaxhighlight lang="json"> { "app": { "windows": [ { "label": "main", "title": "Main Window", "visible": false }, { "label": "splashscreen", "title": "Loading...", "url": "/splashscreen", "width": 400, "height": 300, "resizable": false, "decorations": false, "center": true } ] } } </syntaxhighlight> <br><br> == WebviewWindow API == ==== 現在のウインドウを取得 ==== フロントエンド (JavaScript / TypeScript) から現在のウインドウを取得する。<br> <br> <syntaxhighlight lang="typescript"> // src/utils/window.ts import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; // 現在のウインドウを取得 const currentWindow = getCurrentWebviewWindow(); // ウインドウ情報を取得 console.log('Label:', await currentWindow.label()); console.log('Title:', await currentWindow.title()); console.log('Size:', await currentWindow.innerSize()); </syntaxhighlight> <br> ==== ウインドウ操作メソッド ==== <syntaxhighlight lang="typescript"> // src/utils/windowOperations.ts import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; export async function minimizeWindow() { const window = getCurrentWebviewWindow(); await window.minimize(); } export async function maximizeWindow() { const window = getCurrentWebviewWindow(); await window.maximize(); } export async function unmaximizeWindow() { const window = getCurrentWebviewWindow(); await window.unmaximize(); } export async function toggleMaximize() { const window = getCurrentWebviewWindow(); const isMaximized = await window.isMaximized(); if (isMaximized) { await window.unmaximize(); } else { await window.maximize(); } } export async function closeWindow() { const window = getCurrentWebviewWindow(); await window.close(); } export async function setWindowTitle(title: string) { const window = getCurrentWebviewWindow(); await window.setTitle(title); } export async function resizeWindow(width: number, height: number) { const window = getCurrentWebviewWindow(); await window.setSize({ width, height }); } export async function centerWindow() { const window = getCurrentWebviewWindow(); await window.center(); } </syntaxhighlight> <br> ==== 全てのウインドウを取得 ==== <syntaxhighlight lang="typescript"> import { getAllWebviewWindows } from '@tauri-apps/api/webviewWindow'; async function listAllWindows() { const windows = await getAllWebviewWindows(); for (const win of windows) { console.log(`Window: ${await win.label()}`); } } </syntaxhighlight> <br> ==== 特定のウインドウを取得 ==== <syntaxhighlight lang="typescript"> import { WebviewWindow } from '@tauri-apps/api/webviewWindow'; async function getSpecificWindow(label: string) { try { const window = await WebviewWindow.getByLabel(label); if (window) { console.log(`Found window: ${label}`); return window; } } catch (error) { console.error(`Window not found: ${label}`); } return null; } </syntaxhighlight> <br><br> == 動的ウインドウ作成 == ==== JavaScript/TypeScript での作成 ==== フロントエンドから動的にウインドウを作成する。<br> <br> <syntaxhighlight lang="typescript"> // src/utils/createWindow.ts import { WebviewWindow } from '@tauri-apps/api/webviewWindow'; export async function createSettingsWindow() { // 既存のウインドウを確認 const existing = await WebviewWindow.getByLabel('settings'); if (existing) { // 既に存在する場合はフォーカス await existing.setFocus(); return existing; } // 新しいウインドウを作成 const webview = new WebviewWindow('settings', { url: '/settings', title: 'Settings', width: 600, height: 500, center: true, resizable: true, }); // ウインドウイベントをリッスン webview.once('tauri://created', () => { console.log('Settings window created'); }); webview.once('tauri://error', (error) => { console.error('Failed to create window:', error); }); return webview; } // ドキュメントウインドウを作成 export async function createDocumentWindow(documentId: string) { const label = `document-${documentId}`; const existing = await WebviewWindow.getByLabel(label); if (existing) { await existing.setFocus(); return existing; } const webview = new WebviewWindow(label, { url: `/document/${documentId}`, title: `Document - ${documentId}`, width: 800, height: 600, }); return webview; } </syntaxhighlight> <br> ==== Rustでの作成 ==== Rustバックエンドから動的にウインドウを作成する。<br> <br> <syntaxhighlight lang="rust"> // src-tauri/src/lib.rs use tauri::{AppHandle, Manager, WebviewUrl, WebviewWindowBuilder}; #[tauri::command] async fn open_settings_window(app: AppHandle) -> Result<(), String> { // 既存のウインドウを確認 if let Some(window) = app.get_webview_window("settings") { window.set_focus().map_err(|e| e.to_string())?; return Ok(()); } // 新しいウインドウを作成 let _window = WebviewWindowBuilder::new( &app, "settings", // ラベル WebviewUrl::App("settings.html".into()) // URL ) .title("Settings") .inner_size(600.0, 500.0) .center() .resizable(true) .build() .map_err(|e| e.to_string())?; Ok(()) } #[tauri::command] async fn open_document_window( app: AppHandle, document_id: String, ) -> Result<(), String> { let label = format!("document-{}", document_id); // 既存のウインドウを確認 if let Some(window) = app.get_webview_window(&label) { window.set_focus().map_err(|e| e.to_string())?; return Ok(()); } let url = format!("/document/{}", document_id); WebviewWindowBuilder::new(&app, &label, WebviewUrl::App(url.into())) .title(format!("Document - {}", document_id)) .inner_size(800.0, 600.0) .build() .map_err(|e| e.to_string())?; Ok(()) } #[tauri::command] async fn close_window(app: AppHandle, label: String) -> Result<(), String> { if let Some(window) = app.get_webview_window(&label) { window.close().map_err(|e| e.to_string())?; } Ok(()) } </syntaxhighlight> <br> ==== setupフックでのウインドウ作成 ==== アプリケーション起動時にsetupフックでウインドウを作成する。<br> <br> <syntaxhighlight lang="rust"> use tauri::{Builder, Manager, WebviewUrl, WebviewWindowBuilder}; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { Builder::default() .setup(|app| { // メインウインドウの設定 let main_window = app.get_webview_window("main").unwrap(); // 追加のウインドウを作成 let _dev_tools = WebviewWindowBuilder::new( app, "dev-tools", WebviewUrl::App("dev-tools.html".into()) ) .title("Developer Tools") .inner_size(400.0, 600.0) .visible(false) // 最初は非表示 .build()?; Ok(()) }) .run(tauri::generate_context!()) .expect("error while running tauri application"); } </syntaxhighlight> <br><br> == マルチウインドウ == ==== ウインドウ間のデータ共有 ==== 状態管理とイベントを使用してウインドウ間でデータを共有する。<br> <br> <syntaxhighlight lang="rust"> // src-tauri/src/lib.rs use std::sync::Mutex; use tauri::{AppHandle, Manager, State}; struct SharedData { documents: Vec<Document>, } #[tauri::command] async fn get_documents(state: State<'_, Mutex<SharedData>>) -> Vec<Document> { let data = state.lock().unwrap(); data.documents.clone() } #[tauri::command] async fn update_document( app: AppHandle, state: State<'_, Mutex<SharedData>>, document: Document, ) -> Result<(), String> { // 状態を更新 { let mut data = state.lock().unwrap(); // ドキュメントを更新 } // 全てのウインドウに通知 app.emit("document-updated", &document) .map_err(|e| e.to_string())?; Ok(()) } </syntaxhighlight> <br> ==== ウインドウ間イベント通信 ==== <syntaxhighlight lang="typescript"> // src/hooks/useWindowEvents.ts import { listen, UnlistenFn } from '@tauri-apps/api/event'; import { useEffect, useState } from 'react'; interface DocumentUpdatedEvent { id: string; title: string; content: string; } export function useDocumentUpdates() { const [documents, setDocuments] = useState<DocumentUpdatedEvent[]>([]); useEffect(() => { let unlisten: UnlistenFn; const setupListener = async () => { unlisten = await listen<DocumentUpdatedEvent>('document-updated', (event) => { console.log('Document updated:', event.payload); setDocuments(prev => { const index = prev.findIndex(d => d.id === event.payload.id); if (index >= 0) { const updated = [...prev]; updated[index] = event.payload; return updated; } return [...prev, event.payload]; }); }); }; setupListener(); return () => { if (unlisten) { unlisten(); } }; }, []); return documents; } </syntaxhighlight> <br> ==== マルチウインドウのベストプラクティス ==== * ウインドウの重複を避ける *: 同じラベルのウインドウが既に存在する場合は、新規作成せずフォーカスを移す。 * リソース管理 *: 不要になったウインドウは適切にクローズする。 * 状態の同期 *: ウインドウ間で状態が一貫していることを保証する。 <br><br> == ウインドウイベント == ==== Rustでのイベントハンドリング ==== <syntaxhighlight lang="rust"> use tauri::{Builder, Manager, WindowEvent}; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { Builder::default() .on_window_event(|window, event| { match event { WindowEvent::Resized(size) => { println!( "Window {} resized to {}x{}", window.label(), size.width, size.height ); } WindowEvent::Moved(position) => { println!( "Window {} moved to ({}, {})", window.label(), position.x, position.y ); } WindowEvent::CloseRequested { api, .. } => { // 閉じる要求をキャンセルして確認ダイアログを表示 api.prevent_close(); // 確認処理後に閉じる // window.close().unwrap(); } WindowEvent::Destroyed => { println!("Window {} destroyed", window.label()); } WindowEvent::Focused(focused) => { if *focused { println!("Window {} focused", window.label()); } else { println!("Window {} unfocused", window.label()); } } WindowEvent::ScaleFactorChanged { scale_factor, .. } => { println!("Scale factor changed to {}", scale_factor); } _ => {} } }) .run(tauri::generate_context!()) .expect("error while running tauri application"); } </syntaxhighlight> <br> ==== TypeScriptでのイベントリスナー ==== <syntaxhighlight lang="typescript"> // src/hooks/useWindowEvent.ts import { useEffect } from 'react'; import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; import { UnlistenFn } from '@tauri-apps/api/event'; export function useWindowEvent( eventType: string, callback: (payload: unknown) => void ) { useEffect(() => { let unlisten: UnlistenFn | undefined; const setup = async () => { const window = getCurrentWebviewWindow(); // @ts-ignore - ウインドウイベントの型定義 unlisten = await window.onWindowEvent(eventType, callback); }; setup(); return () => { if (unlisten) { unlisten(); } }; }, [eventType, callback]); } // 使用例 function MyComponent() { useWindowEvent('resized', (payload) => { console.log('Window resized:', payload); }); useWindowEvent('focused', (payload) => { console.log('Focus changed:', payload); }); return <div>Window Event Demo</div>; } </syntaxhighlight> <br> ==== 閉じる確認ダイアログ ==== <syntaxhighlight lang="rust"> use tauri::{Builder, Manager, WindowEvent}; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { Builder::default() .on_window_event(|window, event| { if let WindowEvent::CloseRequested { api, .. } = event { // メインウインドウの閉じる要求を処理 if window.label() == "main" { // 閉じるを一時的にキャンセル api.prevent_close(); // フロントエンドに確認を依頼 let _ = window.emit("confirm-close", ()); } } }) .invoke_handler(tauri::generate_handler![confirm_close]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } #[tauri::command] async fn confirm_close(app: tauri::AppHandle, confirmed: bool) { if confirmed { // アプリケーションを終了 app.exit(0); } } </syntaxhighlight> <br> <syntaxhighlight lang="typescript"> // src/components/App.tsx import { listen } from '@tauri-apps/api/event'; import { invoke } from '@tauri-apps/api/core'; import { useEffect, useState } from 'react'; export function App() { const [showConfirmDialog, setShowConfirmDialog] = useState(false); useEffect(() => { let unlisten: (() => void) | undefined; const setup = async () => { unlisten = await listen('confirm-close', () => { setShowConfirmDialog(true); }); }; setup(); return () => { if (unlisten) unlisten(); }; }, []); const handleClose = async (confirmed: boolean) => { setShowConfirmDialog(false); await invoke('confirm_close', { confirmed }); }; return ( <div> {/* アプリケーションコンテンツ */} {showConfirmDialog && ( <div className="dialog"> <p>アプリケーションを終了しますか?</p> <button onClick={() => handleClose(true)}>はい</button> <button onClick={() => handleClose(false)}>いいえ</button> </div> )} </div> ); } </syntaxhighlight> <br><br> == window-stateプラグインによる状態保持 == ==== プラグインのインストール ==== Cargo.tomlファイルに依存関係を追加する。<br> <br> <syntaxhighlight lang="toml"> # src-tauri/Cargo.toml [dependencies] tauri = { version = "2", features = ["macos-private-api"] } tauri-plugin-window-state = "2" </syntaxhighlight> <br> ==== プラグインの初期化 ==== <syntaxhighlight lang="rust"> // src-tauri/src/lib.rs use tauri::Builder; use tauri_plugin_window_state::WindowState; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { Builder::default() .plugin(WindowState::default()) .run(tauri::generate_context!()) .expect("error while running tauri application"); } </syntaxhighlight> <br> ==== 状態の保存と復元 ==== window-stateプラグインは、以下に示すウインドウの状態を自動的に保存・復元する。<br> <br> * 位置 (x, y) * サイズ (width, height) * 最大化状態 * フルスクリーン状態 <br> <syntaxhighlight lang="rust"> use tauri::Builder; use tauri_plugin_window_state::{WindowState, StateFlags}; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { Builder::default() .plugin( WindowState::default() // 保存する状態を指定 .with_state_flags( StateFlags::SIZE | StateFlags::POSITION | StateFlags::MAXIMIZED | StateFlags::FULLSCREEN ) ) .run(tauri::generate_context!()) .expect("error while running tauri application"); } </syntaxhighlight> <br> ==== 手動での保存と復元 ==== <syntaxhighlight lang="rust"> use tauri::{AppHandle, Manager}; use tauri_plugin_window_state::{WindowState, StateFlags}; #[tauri::command] async fn save_window_state(app: AppHandle) -> Result<(), String> { let state = app.state::<WindowState>(); state.save(StateFlags::all()) .map_err(|e| e.to_string())?; Ok(()) } #[tauri::command] async fn restore_window_state(app: AppHandle) -> Result<(), String> { let state = app.state::<WindowState>(); state.restore(StateFlags::all(), Some("main")) .map_err(|e| e.to_string())?; Ok(()) } </syntaxhighlight> <br><br> == React + TypeScriptでのサンプルコード == ==== ウインドウ管理カスタムフック ==== <syntaxhighlight lang="typescript"> // src/hooks/useWindowManager.ts import { useState, useEffect, useCallback } from 'react'; import { getCurrentWebviewWindow, WebviewWindow, WindowOptions } from '@tauri-apps/api/webviewWindow'; import { invoke } from '@tauri-apps/api/core'; // ウインドウ情報を表す型 interface WindowInfo { label: string; // ウインドウの一意識別子 title: string; // ウインドウタイトル isMaximized: boolean; // 最大化状態かどうか isMinimized: boolean; // 最小化状態かどうか isVisible: boolean; // 表示状態かどうか } export function useWindowManager() { const [currentWindow, setCurrentWindow] = useState<WebviewWindow | null>(null); // 現在のウインドウインスタンス const [windowInfo, setWindowInfo] = useState<WindowInfo | null>(null); // ウインドウ情報 // 初期化 : 現在のウインドウを取得して情報をセット useEffect(() => { const init = async () => { // 現在のウインドウを取得 const window = getCurrentWebviewWindow(); setCurrentWindow(window); // ウインドウの各種情報を非同期で取得 const info: WindowInfo = { label: window.label, title: await window.title(), isMaximized: await window.isMaximized(), isMinimized: await window.isMinimized(), isVisible: await window.isVisible(), }; setWindowInfo(info); }; init(); }, []); // ウインドウを最小化 const minimize = useCallback(async () => { if (currentWindow) { await currentWindow.minimize(); } }, [currentWindow]); // ウインドウを最大化 const maximize = useCallback(async () => { if (currentWindow) { await currentWindow.maximize(); } }, [currentWindow]); // ウインドウの最大化を解除 const unmaximize = useCallback(async () => { if (currentWindow) { await currentWindow.unmaximize(); } }, [currentWindow]); // ウインドウの最大化をトグル (最大化 / 解除を切り替え) const toggleMaximize = useCallback(async () => { if (currentWindow) { const isMax = await currentWindow.isMaximized(); if (isMax) { await currentWindow.unmaximize(); // 最大化を解除 } else { await currentWindow.maximize(); // 最大化する } } }, [currentWindow]); // ウインドウを閉じる const close = useCallback(async () => { if (currentWindow) { await currentWindow.close(); } }, [currentWindow]); // ウインドウタイトルを設定 const setTitle = useCallback(async (title: string) => { if (currentWindow) { await currentWindow.setTitle(title); } }, [currentWindow]); // 新しいウインドウを作成 (既存の場合はフォーカス) const createWindow = useCallback(async ( label: string, // ウインドウラベル options: WindowOptions // ウインドウオプション ) => { // 同じラベルのウインドウが既に存在するか確認 const existing = await WebviewWindow.getByLabel(label); if (existing) { await existing.setFocus(); // 既存ウインドウにフォーカス return existing; } // 新しいウインドウを作成 const newWindow = new WebviewWindow(label, options); return newWindow; }, []); // 設定ウインドウを開く (Rustコマンド経由) const openSettingsWindow = useCallback(async () => { await invoke('open_settings_window'); }, []); // フックの利用者に公開する値と関数 return { currentWindow, // 現在のウインドウインスタンス windowInfo, // ウインドウ情報 minimize, // 最小化関数 maximize, // 最大化関数 unmaximize, // 最大化解除関数 toggleMaximize, // 最大化トグル関数 close, // 閉じる関数 setTitle, // タイトル設定関数 createWindow, // ウインドウ作成関数 openSettingsWindow, // 設定ウインドウを開く関数 }; } </syntaxhighlight> <br> ==== カスタムタイトルバーコンポーネント ==== <syntaxhighlight lang="typescript"> // src/components/TitleBar.tsx import React from 'react'; import { useWindowManager } from '../hooks/useWindowManager'; import './TitleBar.css'; interface TitleBarProps { title?: string; } export function TitleBar({ title = 'My Application' }: TitleBarProps) { const { minimize, maximize, toggleMaximize, close } = useWindowManager(); const [isMaximized, setIsMaximized] = React.useState(false); const handleMaximize = async () => { await toggleMaximize(); setIsMaximized(!isMaximized); }; return ( <div className="titlebar" data-tauri-drag-region> <div className="titlebar-title" data-tauri-drag-region> {title} </div> <div className="titlebar-controls"> <button className="titlebar-button minimize" onClick={minimize} aria-label="最小化" > <svg width="12" height="12" viewBox="0 0 12 12"> <rect y="5" width="12" height="2" fill="currentColor" /> </svg> </button> <button className="titlebar-button maximize" onClick={handleMaximize} aria-label={isMaximized ? '元に戻す' : '最大化'} > {isMaximized ? ( <svg width="12" height="12" viewBox="0 0 12 12"> <rect x="2" y="4" width="8" height="8" fill="none" stroke="currentColor" strokeWidth="1" /> <rect x="0" y="0" width="8" height="8" fill="var(--bg-color)" stroke="currentColor" strokeWidth="1" /> </svg> ) : ( <svg width="12" height="12" viewBox="0 0 12 12"> <rect x="0" y="0" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="1" /> </svg> )} </button> <button className="titlebar-button close" onClick={close} aria-label="閉じる" > <svg width="12" height="12" viewBox="0 0 12 12"> <line x1="1" y1="1" x2="11" y2="11" stroke="currentColor" strokeWidth="1.5" /> <line x1="11" y1="1" x2="1" y2="11" stroke="currentColor" strokeWidth="1.5" /> </svg> </button> </div> </div> ); } </syntaxhighlight> <br> <syntaxhighlight lang="css"> /* src/components/TitleBar.css */ .titlebar { display: flex; justify-content: space-between; align-items: center; height: 32px; background-color: #1e1e1e; color: #ffffff; user-select: none; } .titlebar-title { flex: 1; padding-left: 12px; font-size: 13px; } .titlebar-controls { display: flex; } .titlebar-button { width: 46px; height: 32px; border: none; background: transparent; color: #ffffff; cursor: pointer; display: flex; align-items: center; justify-content: center; } .titlebar-button:hover { background-color: #3c3c3c; } .titlebar-button.close:hover { background-color: #e81123; } </syntaxhighlight> <br><br> == トラブルシューティング == ==== ウインドウが表示されない ==== * 原因 *: <code>visible: false</code>が設定されている、または初期化エラーが発生している。 * 解決方法 *: <syntaxhighlight lang="json"> // tauri.conf.json で visible を確認 { "app": { "windows": [{ "label": "main", "visible": true }] } } </syntaxhighlight> <br> ==== マルチウインドウでイベントが届かない ==== * 原因 *: イベントのスコープが正しく設定されていない。 * 解決方法 *: <syntaxhighlight lang="rust"> // 全てのウインドウにイベントを送信 app.emit("event-name", &payload)?; // 特定のウインドウに送信 app.emit_to("window-label", "event-name", &payload)?; </syntaxhighlight> <br> ==== ウインドウサイズが保存されない ==== * 原因 *: window-stateプラグインが正しく設定されていない。 * 解決方法 *: <syntaxhighlight lang="rust"> // プラグインを正しく初期化 Builder::default() .plugin(WindowState::default()) </syntaxhighlight> <br> ==== クロスプラットフォームでの挙動の違い ==== * 原因 *: OSごとのウインドウ管理の実装差異。 * 解決方法 *: <syntaxhighlight lang="rust"> use tauri::utils::platform; // プラットフォーム固有の処理 #[cfg(target_os = "macos")] { // MacOS固有の処理 } #[cfg(target_os = "windows")] { // Windows固有の処理 } #[cfg(target_os = "linux")] { // Linux固有の処理 } </syntaxhighlight> <br><br> == 関連情報 == * [https://v2.tauri.app/reference/javascript/api/namespacewebviewWindow/ Tauri WebviewWindow API] * [https://v2.tauri.app/reference/config/#windowconfig Window Configuration] * [https://github.com/tauri-apps/tauri-plugin-window-state window-state プラグイン] * [[Tauriの基礎 - 状態管理]] * [[Tauriの基礎 - メニューとシステムトレイ]] * [[Tauriの基礎 - セキュリティモデル]] <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,電気回路,電子回路,基板,プリント基板,Tauri,ウインドウ管理,Window Management,WebviewWindow,マルチウインドウ,デスクトップアプリ |description={{PAGENAME}} - Tauriアプリケーションにおけるウインドウ管理の基本から応用まで詳しく解説 | This page is {{PAGENAME}} about Tauri window management |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:Rust]]
Tauriの基礎 - ウインドウ管理
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse