Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

3. 基本ウィジェットとユーザー入力の扱い方

テキスト表示とRichTextによる装飾

画面に文字を表示するための最も基本的な部品がラベル(label)です。egui では用途に合わせていくつかのショートカットメソッドが用意されています。

#![allow(unused)]
fn main() {
ui.heading("大きな見出し文字");
ui.label("通常の本文テキスト");
ui.monospace("let x = 42; // 等幅フォント(コード表示向き)");
ui.small("小さな補足テキスト");
}

さらに、文字の大きさや色、太字、下線、背景色などを細かく指定したいときは、文字列を egui::RichText で包んで渡します。

#![allow(unused)]
fn main() {
use eframe::egui::{self, Color32, RichText};

ui.label(
    RichText::new("重要なお知らせ")
        .size(20.0) // フォントサイズ(ポイント)
        .color(Color32::from_rgb(255, 100, 100)) // 文字色(RGB指定)
        .strong(), // 太字(環境に応じた強調表示)
);

ui.label(
    RichText::new("ハイライト付きの文字")
        .background_color(Color32::DARK_BLUE)
        .color(Color32::WHITE)
        .italics() // 斜体
        .underline(), // 下線
);
}

RichText は ui.label() だけでなく、ui.button(RichText::new("削除").color(Color32::RED)) のように、ボタンやチェックボックスの見出し文字にもそのまま使うことができます。

ボタンとResponseによるイベント判定

egui に配置するすべてのウィジェットは、描画メソッドの戻り値として egui::Response という構造体を返します。この Response の中に、「今この部品がクリックされたか」「マウスカーソルが乗っているか」「値が変更されたか」といったすべての情報が詰まっています。

flowchart LR
    Widget["ui.button("保存")"] --> Resp["戻り値: egui::Response"]
    Resp --> C1[".clicked() : 左クリックされたか"]
    Resp --> C2[".secondary_clicked() : 右クリックされたか"]
    Resp --> C3[".double_clicked() : ダブルクリックされたか"]
    Resp --> C4[".hovered() : マウスが乗っているか"]
    Resp --> C5[".changed() : 内部の値が書き換わったか"]

ボタンのさまざまな操作を判定するコード例を見てみましょう。

#![allow(unused)]
fn main() {
let response = ui.button("ここをクリック");

if response.clicked() {
    println!("左クリックされました!");
}
if response.secondary_clicked() {
    println!("右クリックされました!");
}
if response.double_clicked() {
    println!("ダブルクリックされました!");
}
if response.hovered() {
    ui.label("いまボタンの上にマウスがあります");
}
}

多くの場合は変数 response に入れず、if ui.button("実行").clicked() { ... } のように直接 if 文につなげて書きます。

テキスト入力と可変参照のバインディング

ユーザーから文字を入力してもらうには、String 型のフィールドの可変参照(&mut String)をテキスト入力ウィジェットに渡します。

▸ 1行入力と複数行入力のショートカット

最も簡単な方法は、ui.text_edit_singleline(1 行)と ui.text_edit_multiline(複数行)を使うことです。

#![allow(unused)]
fn main() {
ui.label("タイトル:");
let res = ui.text_edit_singleline(&mut self.title);
if res.changed() {
    // 文字が1文字でも入力・削除された瞬間に実行される
    println!("現在のタイトル: {}", self.title);
}

ui.label("メモ本文:");
ui.text_edit_multiline(&mut self.memo);
}

▸ TextEdit構造体による詳細な設定

入力欄が空のときに薄い文字でヒントを表示する「プレースホルダー(hint_text)」や、パスワード入力用の伏せ字(password(true))、横幅の指定などを行いたい場合は、egui::TextEdit 構造体を作って ui.add() に渡します。

#![allow(unused)]
fn main() {
// ヒント文字つきの1行入力
ui.add(
    egui::TextEdit::singleline(&mut self.username)
        .hint_text("ユーザー名を入力してください...")
        .desired_width(200.0),
);

// パスワード入力(文字が ● で隠れる)
ui.add(
    egui::TextEdit::singleline(&mut self.password)
        .password(true)
        .hint_text("パスワード"),
);
}

また、1 行入力欄で Enter キーが押された瞬間を検知したいときは、以下のように判定できます。

#![allow(unused)]
fn main() {
let response = ui.text_edit_singleline(&mut self.input_text);
if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
    // Enterキーで入力を確定したときの処理
    self.submit();
}
}

数値入力と選択ウィジェット

数値の調整や、複数の選択肢から選ばせるための代表的なウィジェットをまとめます。

▸ Slider(スライダー)と DragValue(ドラッグ数値入力)

数値を直感的に変えるには egui::Slider や egui::DragValue に数値変数(i32、f32、f64 など)の可変参照を渡します。

#![allow(unused)]
fn main() {
// 0.0 から 100.0 の範囲で動かすスライダー(単位サフィックスつき)
ui.add(
    egui::Slider::new(&mut self.volume, 0.0..=100.0)
        .text("音量")
        .suffix("%"),
);

// 左右にドラッグするかダブルクリックで直接数値入力できる部品
ui.horizontal(|ui| {
    ui.label("X座標:");
    ui.add(egui::DragValue::new(&mut self.pos_x).speed(0.5));
});
}

▸ Checkbox(チェックボックス)

ON / OFF の真偽値(bool)を切り替えるには ui.checkbox を使います。

#![allow(unused)]
fn main() {
ui.checkbox(&mut self.enable_notification, "通知を有効にする");
}

▸ RadioButton(ラジオボタン)と SelectableValue

複数の選択肢から 1 つだけを選ばせるときは、Rust の列挙型(enum)に PartialEq トレイトを派生(#[derive(PartialEq)])させておき、ui.radio_value またはボタン風の ui.selectable_value を使います。

#![allow(unused)]
fn main() {
#[derive(PartialEq, Clone, Copy, Debug)]
enum Priority {
    Low,
    Medium,
    High,
}

// update メソッド内での描画
ui.horizontal(|ui| {
    ui.label("優先度:");
    ui.radio_value(&mut self.priority, Priority::Low, "低");
    ui.radio_value(&mut self.priority, Priority::Medium, "中");
    ui.radio_value(&mut self.priority, Priority::High, "高");
});
}

ui.radio_value の代わりに ui.selectable_value を使うと、タブ切り替えボタンのような見た目になります。

▸ ComboBox(ドロップダウンリスト)

選択肢が多くて画面の場所を節約したいときは、egui::ComboBox を使ってクリック時に開くドロップダウンメニューを作ります。

#![allow(unused)]
fn main() {
egui::ComboBox::from_label("優先度の選択")
    .selected_text(format!("{:?}", self.priority))
    .show_ui(ui, |ui| {
        ui.selectable_value(&mut self.priority, Priority::Low, "低 (Low)");
        ui.selectable_value(&mut self.priority, Priority::Medium, "中 (Medium)");
        ui.selectable_value(&mut self.priority, Priority::High, "高 (High)");
    });
}

ツールチップと有効・無効状態の制御

実用的なアプリでは、「なぜ今このボタンを押せないのか」をユーザーに伝えたり、条件が揃うまでボタンをグレーアウト(無効化)したりする工夫が欠かせません。

▸ ホバー時のツールチップ表示(on_hover_text)

Response に対して .on_hover_text("説明文") をつなげるだけで、マウスカーソルを乗せたときに補足説明のポップアップ(ツールチップ)を表示できます。

#![allow(unused)]
fn main() {
if ui
    .button("設定をリセット")
    .on_hover_text("すべての設定を初期状態に戻します(元に戻せません)")
    .clicked()
{
    self.reset();
}
}

▸ ウィジェットの有効・無効の切り替え(add_enabled / add_enabled_ui)

たとえば「テキスト欄が空でないときだけ送信ボタンを押せるようにする」場合は、ui.add_enabled または複数の部品をまとめて無効化できる ui.add_enabled_ui を使います。

#![allow(unused)]
fn main() {
let can_submit = !self.username.trim().is_empty();

if ui
    .add_enabled(can_submit, egui::Button::new("送信する"))
    .on_disabled_hover_text("ユーザー名を入力すると送信できます")
    .clicked()
{
    println!("{} さんを登録しました", self.username);
}
}

on_disabled_hover_text を組み合わせると、ボタンが無効化されているときにマウスを乗せた人に対して「どうすれば押せるようになるか」を親切に案内できます。

次章では、これらのウィジェットを画面上で美しく整列させるためのレイアウトシステムと、パネル・ウィンドウによる画面分割の仕組みを解説します。