Rustはたまに触る程度で継続的にプログラミングを行っていないので時間が立つと忘れてしまいます。継続的に触れる機会としてなにかアプリケーションを作ろうと思います。ということでまずは見た目から。Rustで気になるGUI crateを試してみます。
どうやらデファクトスタンダードなGUI crateは現時点では存在せず、安定度もまちまちなようです。
そこで気になるcrateを使ってビルドができるのか?軽くサンプルプログラムを動作させて問題がなさそうか?、調べて見たいと思います。
2024/04-5月頃の情報になります。
dioxusはデスクトップ、モバイル、Web、TUI(テキストベースのUI)などをカバーするフレームワークです。React系の設計思想です。クロスプラットフォーム対応です。
フルスタックを謳うフレームワークで機能が充実している分、必要なcrateが多いです。JavaScriptフレームワークのような専用コマンドが用意されています。
sudo apt install -y gcc sudo apt install -y make cargo install dioxus-cli@0.5.4 dx new ✔ 🤷 Which sub-template should be expanded? · Desktop 🤷 Project Name: test01 ✔ 🤷 How do you want to create CSS? · Vanilla ✔ 🤷 Should the application use the Dioxus router? · true cd test01 sudo apt install -y pkg-config sudo apt install -y librust-gio-sys-dev sudo apt install -y libgtk-3-dev sudo apt install -y libsoup-3.0-dev sudo apt install -y libjavascriptcoregtk-4.1-dev sudo apt install -y libwebkit2gtk-4.1-dev sudo apt install -y libxdo-dev dx serve --platform desktop 下記が場合によって必要かもしれません sudo apt install -y libglib2.0-dev
フレームワーク提供のコマンドで実行環境向けインストーラーが作成されるらしい。詳しくはこちらを参照。
main.rsに下記を追加(オプショナル。実行時にDOS窓が表示されなくなる。他のcrateにも有効) #![windows_subsystem = "windows"]
Dioxus.tomlに下記を追加 [bundle] resources = ["**/main.css", "**/header.svg" ]
dx bundle --release --platform desktop Failed to bundle project: BundlerError( Error { context: "Failed to build data folders and files", source: BundlerError( Error { context: "Failed to copy resource files", source: IoError( Os { code: 36, kind: InvalidFilename, message: "File name too long", }, ), }, ), }, )
成果物はネイティブアプリケーションではありませんでした。Electronのような実行環境の中でロジックが動くイメージでした。そのため、リモートに画面を表示することができません。
クロスコンパイルはBundlerErrorが出て先に進みませんでした。distフォルダーにassetsフォルダーの内容がコピーされているので動いてそうですが原因がよくわかりませんでした。
Assetsのドキュメントを見るとmanganisという別の仕組みが必要なようですがまだ不安定な印象です。
floemはLapceというRustで書かれたエディターで使われているUIフレームワークです。クロスプラットフォーム対応でXilemや Leptos等に影響を受けたリアクティブ系のフレームワークのようです。
State管理はSolidJSと同様のアプローチのようです。
エディターというアプリケーションの実需で使用されているので安定度は高そうです。
# Cargo.toml [dependencies] floem = "0.1.1" sudo apt install -y gcc cargo b 画面を最大化した場合、落ちる cargo r failed to present the surface buffer: PlatformError(Some("Failed to draw image to window"), Some(X11(ConnectionError(MaximumRequestLengthExceeded))))
READMEにあるものを流用。
#![windows_subsystem = "windows"] use floem::reactive::create_signal; use floem::view::View; use floem::views::{h_stack, label, v_stack, Decorators}; use floem::widgets::button; fn app_view() -> impl View { // Create a reactive signal with a counter value, defaulting to 0 let (counter, set_counter) = create_signal(0); // Create a vertical layout v_stack(( // The counter value updates automatically, thanks to reactivity label(move || format!("Value: {}", counter.get())), // Create a horizontal layout h_stack(( button(|| "Increment").on_click_stop(move |_| { set_counter.update(|value| *value += 1); }), button(|| "Decrement").on_click_stop(move |_| { set_counter.update(|value| *value -= 1); }), )), )) } fn main() { floem::launch(app_view); }
sudo apt install -y mingw-w64 cargo build --target x86_64-pc-windows-gnu
コードがシンプルで良さそうですが、X Window上で画面を最大化するだけで落ちてしまうのは不便だし安定度が疑わしくなってしまいます。クロスコンパイルしてWindows環境で実行した際には最大化しても問題ありませんでした。
まだ知名度は低いので日本語の情報は少ないです。
icedはElmの設計思想に影響を受けた型安全なクロスプラットフォームのUIフレームワークです。Webまでカバーしているようですが、詳細は不明です。
# Cargo.toml [dependencies] iced = "0.12.1" sudo apt install -y gcc cargo b
Exampleより流用。
#![windows_subsystem = "windows"] use iced::widget::{button, column, text}; use iced::{Alignment, Element, Sandbox, Settings}; pub fn main() -> iced::Result { Counter::run(Settings::default()) } struct Counter { value: i32, } #[derive(Debug, Clone, Copy)] enum Message { IncrementPressed, DecrementPressed, } impl Sandbox for Counter { type Message = Message; fn new() -> Self { Self { value: 0 } } fn title(&self) -> String { String::from("Counter - Iced") } fn update(&mut self, message: Message) { match message { Message::IncrementPressed => { self.value += 1; } Message::DecrementPressed => { self.value -= 1; } } } fn view(&self) -> Element<Message> { column![ button("Increment").on_press(Message::IncrementPressed), text(self.value).size(50), button("Decrement").on_press(Message::DecrementPressed) ] .padding(20) .align_items(Alignment::Center) .into() } }
sudo apt install -y mingw-w64 cargo build --target x86_64-pc-windows-gnu
コードがシンプルで良さそうです。クロスコンパイルも動作も問題ないようです。
ボタンの見た目がボタンらしくないのですが、サンプルを見るとちゃんとしているのでそのあたりの研究が必要かもしれません。レイアウト系がシンプルな仕組みのみで弱いかもしれません。
日本語の情報を多めです。ただし初心者向けのものが多いようです。
Viziaは宣言的でリアクティブなクロスプラットフォーム対応のUIフレームワークです。アニメーションやGPUアクセラレーター対応のようです。
# Cargo.toml [dependencies] #vizia = "0.1.0" vizia = {git = "https://github.com/vizia/vizia"} sudo apt install -y gcc cargo b
Bookより流用。
#![windows_subsystem = "windows"] use vizia::prelude::*; #[derive(Lens)] pub struct AppData { count: i32, } pub enum AppEvent { Increment, Decrement, } impl Model for AppData { fn event(&mut self, _cx: &mut EventContext, event: &mut Event) { event.map(|app_event, _meta| match app_event { AppEvent::Decrement => self.count -= 1, AppEvent::Increment => self.count += 1, }); } } fn main() { let _ = Application::new(|cx| { AppData { count: 0 }.build(cx); HStack::new(cx, |cx| { Button::new(cx, |cx| Label::new(cx, "Decrement")) .on_press(|ex| ex.emit(AppEvent::Decrement)) .class("dec"); Button::new(cx, |cx| Label::new(cx, "Increment")) .on_press(|ex| ex.emit(AppEvent::Increment)) .class("inc"); Label::new(cx, AppData::count); }) .child_space(Stretch(1.0)) .col_between(Pixels(20.0)); }) .title("Counter") .inner_size((400, 100)) .run(); }
sudo apt install -y mingw-w64 cargo build --target x86_64-pc-windows-gnu
0.1.0ではコンパイルできませんでした。それ以外の部分では問題がありませんでした。
バージョンがまだ若いので今後大きな変化が起きる恐れがあります。
各crateはほぼ何らかのJavaScriptフレームワークの影響を受けたものになっているので過去に使用したことがある場合は学習コストを抑えて使っていける可能性があります。
dioxusはエコシステムが充実しているので今後の期待度が高いですが、覚えることも多そうです。また、リモートに画面を表示することができなかったのが惜しいところです。
floemはシンプルに書けそうですが、最大化するだけで落ちるといった品質面に不安が残る結果となりました。またカッコが多くなりそうです。
icedはシンプルに書けそうですが、今回試した中でボタンの見た目が一番ネイティブ表示から遠いのでカスタマイズの可能性をもう少し調べる必要がありそうです。
Viziaは動作しますが、まだ公式バージョンが安定しておらず、バージョンも若いため今後大きな変化が起こる可能性があり、現時点で使用していくには勇気が必要です。
ただ、この記事を書いている最中もアップデートが進んでおり、上記紹介したサンプルも次のリビジョンで書き方が異なっているものもあります。これらのcrateを採用するにしても、まだプロトタイプレベルの使用に抑えておいたほうがいいかもしれません。