はじめに
Rustでデスクトップアプリケーションを開発する際、クロスプラットフォーム対応のGUIライブラリの選択は重要です。既存の選択肢として、egui、Tauri、iframeworkなどがありますが、今回は成熟したC++ライブラリであるwxWidgetsをRustから使える「wxDragon」を紹介します。
wxDragonは、30年以上の歴史を持つwxWidgetsをRustから安全に利用できるようにするラッパーライブラリです。ネイティブなルック&フィールを持つアプリケーションを、Rustの安全性と表現力を活かして開発できます。
wxDragonとは
wxDragonは、wxWidgetsのC++ APIをCラッパー経由でRustから利用可能にするプロジェクトです。2024年1月にv0.4.0がリリースされ、XRCサポートやクリップボード機能、高DPI対応など、多くの新機能が追加されました。
プロジェクトの特徴
wxDragonの設計は、Rustの安全性を最大限に活かしながら、wxWidgetsの豊富な機能にアクセスできるよう工夫されています。C++のwxWidgetsをC APIでラップし、それをbindgenで自動的にRustバインディングを生成。さらに、その上に安全なRust APIを構築するという多層構造になっています。
ビルドシステムも特徴的で、wxWidgetsのソースコードを自動的にダウンロード・ビルドするため、開発者は事前にwxWidgetsをインストールする必要がありません。CMakeとCargoが連携して、必要なライブラリを静的リンクで組み込みます。
イベント処理においても、wxWidgetsのネイティブなイベントシステムとRustのクロージャを自然に統合。メモリ安全性を保ちながら、柔軟なイベントハンドリングが可能です。
なぜwxDragonを選ぶのか
他のRust GUIフレームワーク(egui、tauri、iced)と比較して、wxDragonは以下の点で異なります。
- ネイティブなルック&フィール: 各プラットフォームのネイティブウィジェットを使用(macOSではCocoa、WindowsではWin32、LinuxではGTK)
- 50以上の豊富なウィジェット: DataView、AUI、メディアプレーヤーなどの高度なコントロールを含む
- 伝統的なデスクトップアプリケーションパターン: 長年の実績があるwxWidgetsの設計思想を継承
環境構築
wxDragonを使い始めるのは簡単です。Rustの開発環境とC++コンパイラがあれば使えます。
必要な環境
# Rustのインストール(未インストールの場合)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# C++コンパイラ(プラットフォームに応じて)
# macOS: Xcodeコマンドラインツール
xcode-select --install
# Windows: Visual Studio Build Tools または MinGW
# Linux: GCCまたはClang
wxWidgetsは自動的にダウンロード・ビルドされるため、別途インストールする必要はありません。
プロジェクトの作成
新しいRustプロジェクトを作成し、Cargo.tomlにwxDragonを追加します。
[dependencies]
wxdragon = { git = "https://github.com/AllenDang/wxDragon" }
基本的な使い方
Hello Worldアプリケーション
最初に、シンプルなウィンドウとボタンを持つアプリケーションを作成してみましょう。
use wxdragon::prelude::*;
fn main() {
wxdragon::main(|_| {
// メインウィンドウの作成
let frame = Frame::builder()
.with_title("Hello, wxDragon!")
.with_size(Size::new(300, 200))
.build();
// 垂直方向のレイアウトマネージャー
let sizer = BoxSizer::builder(Orientation::Vertical).build();
// ボタンの作成
let button = Button::builder(&frame)
.with_label("クリックしてください")
.build();
// ボタンクリックイベントの処理
button.on_click(|_| {
println!("ボタンがクリックされました!");
});
// レイアウトにボタンを追加
sizer.add(
&button,
1, // 伸縮比率
SizerFlag::AlignCenterHorizontal | SizerFlag::AlignCenterVertical,
0, // ボーダー幅
);
// フレームにレイアウトを設定
frame.set_sizer(sizer, true);
// ウィンドウを表示
frame.show(true);
frame.centre();
});
}
このコードの特徴的な点は、wxDragonがビルダーパターンを採用していることです。各ウィジェットの作成時に、必要なプロパティをメソッドチェーンで設定できます。また、イベントハンドラーはRustのクロージャとして自然に記述できます。
v0.4.0の新機能
最新バージョンでは、開発効率を大幅に向上させる新機能が追加されました。
クリップボードサポート
テキスト、ファイル、ビットマップのクリップボード操作が可能になりました。
use wxdragon::prelude::*;
// テキストをクリップボードにコピー
clipboard::set_text("Hello from Rust!");
// ファイルをクリップボードにコピー
clipboard::set_files(&["path/to/file1.txt", "path/to/file2.png"]);
// クリップボードの内容を取得
if let Some(text) = clipboard::get_text() {
println!("クリップボード: {}", text);
}
タイマーウィジェット
定期的なイベント処理やコールバックのスケジューリングが可能です。
let timer = Timer::new();
timer.start(1000); // 1秒間隔
timer.on_timer(|_| {
println!("タイマーイベント発火!");
});
高DPI対応(BitmapBundle)
高解像度ディスプレイに対応した画像管理機能です。
let bundle = BitmapBundle::from_files(&[
"icon_16.png",
"icon_32.png",
"icon_64.png"
]);
button.set_bitmap_bundle(bundle);
高度な機能
ノートブック(タブ)コントロール
複数のページを持つタブインターフェースの実装例です。
use wxdragon::prelude::*;
fn create_notebook_app() {
wxdragon::main(|_| {
let frame = Frame::builder()
.with_title("タブ付きアプリケーション")
.with_size(Size::new(600, 400))
.build();
let notebook = Notebook::builder(&frame).build();
// 基本設定タブ
let basic_panel = Panel::builder(¬ebook).build();
let basic_sizer = BoxSizer::builder(Orientation::Vertical).build();
let checkbox = CheckBox::builder(&basic_panel)
.with_label("有効にする")
.build();
basic_sizer.add(&checkbox, 0, SizerFlag::All, 5);
basic_panel.set_sizer(basic_sizer, true);
// 詳細設定タブ
let advanced_panel = Panel::builder(¬ebook).build();
let advanced_sizer = BoxSizer::builder(Orientation::Vertical).build();
let slider = Slider::builder(&advanced_panel)
.with_range(0, 100)
.with_value(50)
.build();
advanced_sizer.add(&slider, 0, SizerFlag::Expand | SizerFlag::All, 5);
advanced_panel.set_sizer(advanced_sizer, true);
// タブの追加
notebook.add_page(&basic_panel, "基本設定", true, None);
notebook.add_page(&advanced_panel, "詳細設定", false, None);
// ページ変更イベント
notebook.on_page_changed(|event_data| {
let new_index = event_data.get_selection().unwrap_or(0);
println!("タブが変更されました: {}", new_index);
});
let main_sizer = BoxSizer::builder(Orientation::Vertical).build();
main_sizer.add(¬ebook, 1, SizerFlag::Expand, 0);
frame.set_sizer(main_sizer, true);
frame.show(true);
});
}
ダイアログの表示
ファイル選択やメッセージ表示など、各種ダイアログの使用例です。
fn show_dialogs(parent: &Frame) {
// メッセージダイアログ
let msg_dialog = MessageDialog::builder(parent)
.with_message("ファイルを保存しますか?")
.with_caption("確認")
.with_style(MessageDialogStyle::YesNo | MessageDialogStyle::Question)
.build();
if msg_dialog.show_modal() == DialogResult::Yes {
// ファイル保存ダイアログ
let file_dialog = FileDialog::builder(parent)
.with_message("保存先を選択")
.with_wildcard("テキストファイル (*.txt)|*.txt|すべてのファイル (*.*)|*.*")
.with_style(FileDialogStyle::Save | FileDialogStyle::OverwritePrompt)
.build();
if file_dialog.show_modal() == DialogResult::Ok {
let path = file_dialog.get_path();
println!("選択されたパス: {}", path);
}
}
}
クロスコンパイル
wxDragonは、macOSからWindowsへのクロスコンパイルをサポートしています。
# 必要なツールのインストール(macOS)
brew install mingw-w64
# Rustターゲットの追加
rustup target add x86_64-pc-windows-gnu
# ビルド実行
cargo build --target=x86_64-pc-windows-gnu --release
ビルドシステムが自動的に適切なコンパイラとリンカーオプションを設定し、スタンドアロンの実行ファイルを生成します。
今後の展望と課題
wxDragonはまだ開発中のプロジェクトですが、既に多くのウィジェットがサポートされています。現在サポートされているウィジェットには、基本的なコントロール(Button、TextCtrl、CheckBox等)、コンテナ(Panel、Notebook、SplitterWindow等)、ダイアログ(MessageDialog、FileDialog等)、高度なコントロール(TreeCtrl、ListCtrl、DataViewCtrl等)などがあります。
現在の制限事項
開発中のプロジェクトであるため、以下の制限があることに注意が必要です。
- プラットフォームサポート: 現在はmacOSでの開発が最も安定しており、Linux/Windowsの自動ビルドサポートは開発中
- ドキュメンテーション: docs.rsでのビルドがネットワークアクセス制限により失敗する問題がある
- wxWidgetsの制限: wxWidgets自体が持つ制限(モダンなUIパターンへの対応が限定的など)も継承している
今後のロードマップ
今後の開発では、残りのウィジェットのサポート、Linux/Windowsビルドの自動化改善、ドキュメントの充実、パフォーマンスの最適化などが予定されています。コミュニティからのフィードバックやコントリビューションも歓迎されています。
まとめ
wxDragonは、Rustでネイティブなデスクトップアプリケーションを開発するための強力な選択肢です。wxWidgetsの成熟した機能とRustの安全性を組み合わせることで、堅牢でクロスプラットフォームなアプリケーションを効率的に開発できます。
特に、既存のwxWidgetsの知識がある開発者や、ネイティブなルック&フィールが重要なアプリケーションを開発する場合に、wxDragonは優れた選択となるでしょう。プロジェクトはGitHubで公開されており、コントリビューションも歓迎されているそうです。
