Rustで簡単GUI開発: eguiフレームワークで日本語対応アプリを作る

## はじめに

Rustでグラフィカルユーザーインターフェース（GUI）を開発するためのライブラリはいくつかありますが、今回は特にシンプルで使いやすい「egui」について紹介します。さらに、日本語表示に対応させる方法も解説します。

## eguiとは？

eguiは「イーグーイ（e-gooey）」と発音し、Rust製の即時モード（Immediate Mode）GUIライブラリです。以下のような特徴があります：

- **Pure Rust製**: 100% Rustで書かれており、`unsafe`コードを含みません
- **クロスプラットフォーム**: WebAssembly（ブラウザ）、Windows、macOS、Linuxで動作
- **即時モード**: シンプルで直感的な状態管理
- **最小限の依存関係**: 基本的な依存パッケージは少なく保たれています

公式サイト: [https://www.egui.rs/](https://www.egui.rs/)

下記サービスでも使われているようで、注目しました

https://rerun.io/

## 即時モードGUIとは

「保持モード（Retained Mode）」GUIでは、ウィジェットを作成し、コールバック関数を設定します。対して、eguiのような「即時モード」GUIでは、UIを毎フレーム再構築し、コードがより直線的でシンプルになります。

## プロジェクトの準備

新しいRustプロジェクトを作成し、eframeを依存関係として追加します：

```bash
# 新しいプロジェクトを作成
cargo new egui_app
cd egui_app
```
Cargo.tomlに依存関係を追加
```bash
cargo add eframe
```

または`Cargo.toml`に直接追加：

```toml
[dependencies]
eframe = "0.31.0"  # 最新バージョンを確認してください
```

## 日本語対応した完全なコード例

以下が、日本語フォントを使用したeguiアプリケーションのコード例です：

```rust
use eframe::egui;
use egui::FontFamily;
use std::sync::Arc;

fn main() -> eframe::Result<()> {
    // ウィンドウの設定
    let options = eframe::NativeOptions {
        viewport: egui::viewport::ViewportBuilder::default()
            .with_inner_size([400.0, 300.0]),
        ..Default::default()
    };
    
    // アプリケーションの実行
    eframe::run_native(
        "My egui App",
        options,
        Box::new(|cc| {
            // 日本語フォントの設定
            setup_custom_fonts(&cc.egui_ctx);
            Ok(Box::new(MyApp::default()))
        }),
    )
}

// フォント設定用の関数
fn setup_custom_fonts(ctx: &egui::Context) {
    // フォント設定を取得
    let mut fonts = egui::FontDefinitions::default();
    
    // 日本語フォント（可変ウェイト）を追加
    fonts.font_data.insert(
        "noto_sans_jp".to_owned(),
        egui::FontData::from_static(include_bytes!("../assets/NotoSansJP-VariableFont_wght.ttf")).into(),
    );
    
    // フォントファミリーに追加
    fonts
        .families
        .entry(FontFamily::Proportional)
        .or_default()
        .insert(0, "noto_sans_jp".to_owned()); // 一番優先度高く追加
    
    // モノスペースフォントにも日本語フォントを追加
    fonts
        .families
        .entry(FontFamily::Monospace)
        .or_default()
        .push("noto_sans_jp".to_owned());
    
    // フォント設定を適用
    ctx.set_fonts(fonts);
}

// アプリケーションの状態を保持する構造体
struct MyApp {
    name: String,
    age: u32,
}

impl Default for MyApp {
    fn default() -> Self {
        Self {
            name: "山田太郎".to_owned(),
            age: 42,
        }
    }
}

// アプリケーションの描画とロジックを実装
impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading("My egui Application");
            ui.horizontal(|ui| {
                ui.label("名前: ");
                ui.text_edit_singleline(&mut self.name);
            });
            ui.add(egui::Slider::new(&mut self.age, 0..=120).text("年齢"));
            if ui.button("年齢+1").clicked() {
                self.age += 1;
            }
            ui.label(format!("こんにちは、{}さん({}歳)", self.name, self.age));
        });
    }
}
```

## 実装手順の解説

### 1. フォントファイルの準備

まず、日本語フォントファイルを準備します：

1. プロジェクトの`assets`フォルダを作成します：
   ```bash
   mkdir -p assets
   ```

2. [Google Fonts - Noto Sans JP](https://fonts.google.com/noto/specimen/Noto+Sans+JP)から日本語フォントをダウンロードします。

3. ダウンロードしたZIPファイルから`NotoSansJP-VariableFont_wght.ttf`を`assets`フォルダに配置します。

### 2. コードの解説

#### フォント設定関数
```rust
fn setup_custom_fonts(ctx: &egui::Context) {
    // ...省略...
}
```
- この関数は、eguiのコンテキストにカスタムフォントを設定します。
- `include_bytes!`マクロを使ってフォントファイルをバイナリに埋め込みます。
- `.into()`メソッドで`FontData`を`Arc<FontData>`に変換します（egui 0.31.xの要件）。

#### フォントファミリーへの割り当て
```rust
fonts.families
    .entry(FontFamily::Proportional)
    .or_default()
    .insert(0, "noto_sans_jp".to_owned());
```
- `FontFamily::Proportional`（プロポーショナルフォント）に日本語フォントを追加します。
- `.insert(0, ...)`で優先度を最高に設定します（他のフォントより先に使われます）。

#### アプリケーション構造
1. `MyApp`構造体でアプリケーションの状態を保持
2. `eframe::App`トレイトを実装し、`update`メソッドでUIを描画
3. `run_native`関数でアプリケーションを起動

## 実行結果

これで、アプリケーションを実行すると、日本語が正しく表示されます：

![Screenshot 2025-03-27 at 12.34.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79562/5789a0bf-d163-4d8e-9cb7-d589a8dd9e12.png)

実際の画面では、日本語文字がきれいに表示され、スライダーやテキスト入力欄が機能します。

## まとめ

eguiを使えば、Rustで簡単にクロスプラットフォームのGUIアプリケーションを開発できます。日本語表示に対応させるためには、適切な日本語フォントを埋め込むだけで済みます。

特筆すべき点：
- 即時モードGUIの直感的なコーディングスタイル
- クロスプラットフォーム対応（デスクトップおよびWeb）
- 日本語フォントの簡単な組み込み方法

これを機に、Rustでの独自のGUIアプリケーション開発にチャレンジしてみようかなと思います！

## 参考リンク

- [egui公式サイト](https://www.egui.rs/)
- [GitHub: emilk/egui](https://github.com/emilk/egui)
- [eframe_template - 新規プロジェクトテンプレート](https://github.com/emilk/eframe_template/)
- [Google Fonts - Noto Sans JP](https://fonts.google.com/noto/specimen/Noto+Sans+JP)