記事ディレクトリ
序文
プログラミング言語を学ぶためには、プログラミング言語の応用を決して放棄してはなりません。C++ などの他のプログラミング言語を学習する場合、文法、データ構造、アルゴリズムだけを学習するのは非常に退屈であり、これは忍耐力の問題です。勉強を面白くするのが今の最善の方法. 勉強していたときの興味の源は、学習と作業効率を向上させるために Windows で豪華なウィンドウを作成することでした. このため、QT、MFC、これらのフレームワークを研究してきました。は非常に優れており、実際に私が望む効果を達成しましたが、開発はより面倒です. その後、qt python を学び、開発は非常に便利になりましたが、新しい問題が再び発生しました。このため、私はこの道で曲がりくねった探検を経験しました。現時点では、Rust を学ぶことも同じです. 学習能力を向上させたい場合は、興味のあるポイントを見つける必要があります. Rust については、Rust の利点を使用して Windows のウィンドウを実現したいと考えています。 Rust の qt などのソリューションは面倒ですが別の記事で紹介します.また、Rust をバックエンドとして使用するクロスプラットフォームの UI フレームワークである Tauri UI もあり、その考え方はフロントエンドの Electron に似ています. html+css レイアウトを使用し、バックエンドは Rust を使用し、アプリをパッケージ化します.その使用法はこの連載の後半で紹介します.また、この記事で紹介する Iced もあります.これは Rust の flutter に似ています. Elm ベースのクロスプラットフォーム GUI フレームワークです。
Iced は、私がより興味を持っている GUI フレームワークです。その開発方法は、私のような Vue を学んできた人にとって非常にフレンドリーであり、Rust の特性に非常に慣れています。また、見た目もかなり高いので覚えています。
アイスの特徴
- 一連の組み込み API を使用した、シンプルで使いやすい
- タイプセーフ、対話型プログラミング モデル
- クロスプラットフォーム (Windows、Mac、Linux、および Web をサポート)
- レスポンシブレイアウト
- ウィジェットに基づく
- カスタムウィジェットをサポート
- 他にも機能があります。Github に移動して表示することをお勧めします
1. プロジェクトをビルドする
1. 普通にプロジェクトを作成する
最初にプロジェクトを作成します
cargo new gui_iced_001
2.アイデアをインポートする
アイデアを使用してプロジェクトをインポートする
3.依存関係を導入する
Cargo.toml を開き、依存関係を記述します。
iced = "0.4"
注意:
2021年以降のバージョンを使用しています。そうでない場合は、公式Webサイトにアクセスして、対応する処理戦略を学ぶことをお勧めしますが、ここでは説明しません.
この時点で、ファイルは次のようになります。
ここまでで、プロジェクトがビルドされました。次のステップは、デモを作成することです。
2. デモを書く
GitHub には Iced の例がたくさんありますが、その中で最も古典的で、公式 Web サイトに書かれている唯一の例は Counter カウンターです。これは、Counter デモがここから実現されるためです。これは非常に単純ですが、落とし穴がたくさんあります. このデモを書くのは大変でした. 2 つの落とし穴について話しましょう. このフレームワークは行と列を区別しません. 例のコードは古すぎます. 私はそれを一歩踏み出しました.一歩ずつ。
以下の内容は公式サイトとはかなり異なる内容となり、公式サイトでは動作しませんので、審査にご注意ください。
1. 書き込み状態
まず、プログラムの状態を書きます.この核となる概念は、VueやReact、Flutterを学習する際に必然的に使われるものです.ここではここでは説明しませんが、直接コードを示します.
struct Counter {
value: i32,
// The local state of the two buttons
increment_button: button::State,
decrement_button: button::State,
}
ここに構造体が定義されていますCounter
。この構造体はウィンドウの状態と見なされ、そのメンバーはvalue
カウンター カウントの値increment_button
とdecrement_button
2 つのボタン + と - の状態を表します。
2. メッセージ タイプを定義する
次のステップは、プログラムで使用されるメッセージ タイプを定義することです. プログラム内の相互作用はシグナルを介して実行されます. Qt はこれを非常にうまく行います. qt またはフロントエンド Vue および他のフレームワークを学習したことがある場合, これは簡単に行うことができます.わかります。
#[derive(Debug, Clone, Copy)]
enum Message {
IncrementPressed,
DecrementPressed,
}
ここでは 2 つのメッセージが定義されています。1 つはIncrementPressed
+ ボタンがクリックされたことを表し、もう 1 つはDecrementPressed
- ボタンがクリックされることを表します。
3.ビューロジックを書く
ここでの公式の例は、カウンターのビューと更新を直接実装することですが、私の調査の後、直接使用することはできません。
Iced プログラムは Application または Sandbox を実装する必要があります. 今のところこれら 2 つが何を意味するかは気にしません. ここでは Sandbox を使用します.
空のサンドボックスは次のようになります
impl Sandbox for Counter {
type Message = ();
fn new() -> Self {
todo!()
}
fn title(&self) -> String {
todo!()
}
fn update(&mut self, message: Self::Message) {
todo!()
}
fn view(&mut self) -> Element<'_, Self::Message> {
todo!()
}
}
上から順番に紹介です
メッセージ
これは現在のウィンドウのすべてのメッセージを表します. これを使用するときは, 定義されたメッセージの列挙を渡す必要があります. たとえば, ここでの使い方は次のようになります.
#[derive(Debug, Clone, Copy)]
enum Message {
IncrementPressed,
DecrementPressed,
}
// ....
type Message = Message;
新しい
ここは一般的にコードを書くのと同じで、自分のインスタンスを返す必要があるのであまり説明しません
fn new() -> Self {
Self {
value: 0, increment_button: Default::default(), decrement_button: Default::default() }
}
タイトル
名前を参照してください。ここでは、現在のウィンドウの名前を返します
fn title(&self) -> String {
String::from("Counter - Iced")
}
アップデート
処理ウィンドウのメッセージ ロジックは次のとおりです. このウィンドウは 2 つのメッセージを処理します. 1 つはIncrementPressed
+ ボタンがクリックされたことです. クリックされた場合, State の値は +1 になります. もう 1 つはDecrementPressed
- ボタンがクリックされたことです.クリックすると、State の値は -1 になります。ここでの処理は非常に単純で、境界値は考慮されていません。
fn update(&mut self, message: Message) {
match message {
Message::IncrementPressed => {
self.value += 1;
}
Message::DecrementPressed => {
self.value -= 1;
}
}
}
意見
ここでウィンドウのレイアウトを返すために、実際にこのウィンドウをビルドするには、ここで Counter のウィンドウ コードは次のようになります。
fn view(&mut self) -> Element<Message> {
Column::new().push(
Text::new("Counter")
).push(
Row::new().push(
Button::new(&mut self.increment_button, Text::new("+"))
.on_press(Message::IncrementPressed).width(Length::Fill),
).push(
Text::new(self.value.to_string()).size(22),
).push(
Button::new(&mut self.decrement_button, Text::new("-"))
.on_press(Message::DecrementPressed).width(Length::Fill),
)
)
.align_items(Alignment::Center).into()
}
ここで使用されているタイム チェーン呼び出しはレイヤーごとに行われていることがわかります. そのコードはフラッターに非常に似ています. フラッターを学んだことがあれば, よく知っているはずです. ここで, このコードを説明するために絵を描きます.ウィンドウは列ごとに 2 行に分割されており、そのレイアウトは赤枠と一致しており、上下に 2 行ずつ配置されています。
注意:
このフレームワークでは、行と列はばかげて区別できません. 列は列を意味し、このフレームワークでは行を意味します.
1行目は Text コンポーネントのみ追加し、初期値を与えるCounter
. 本来はここで中国語を使うつもりだったのです计数器
が、これは中国語に対応していません。
Column::new().push(
Text::new("Counter")
)
2 行目には、Row コンポーネント (コンポーネント) が追加され列
、3 つのコンポーネントが追加されます。これらは、+ および - ボタンである 2 つのボタンと、現在の値を表示するためのテキスト コンポーネントです。
//...
.push(
Row::new().push(
Button::new(&mut self.increment_button, Text::new("+"))
.on_press(Message::IncrementPressed).width(Length::Fill),
).push(
Text::new(self.value.to_string()).size(22),
).push(
Button::new(&mut self.decrement_button, Text::new("-"))
.on_press(Message::DecrementPressed).width(Length::Fill),
)
)
したがって、ウィンドウのレイアウトは次のようになります
4. main 関数を書く
書かれたウィンドウは自動的に実行できません。開始する必要があります。通常、メイン関数でウィンドウを開始します。ここで簡単になります。ここにコードを直接貼り付けます
fn main() -> iced::Result {
Counter::run(Settings::default())
}
ウィンドウを開始するには, ウィンドウの run メソッドを呼び出すだけです. これは Settings に渡されてウィンドウの初期状態を設定します. ここでは, デフォルトの状態が直接使用されます. 後でさらに深く知りたい場合は, ここに特別なそれを説明する問題。
3. 運用効果
この時点で、現在作成されているデモを実行します
注意:
完全なコードは記事の最後にあります。コードを入力するのが面倒な場合は、直接コピーできます。
要約する
今号は Rust の GUI フレームワーク Iced を紹介するもので、探索の末、ようやく Counter Demo をビルドしました。経験から言うと、このフレームワークは想像していたほど良くはないと思います. これは確かに Rust のネイティブ GUI フレームワークであり、彼が言った機能を備えています. 確かに美しいですが、最大の問題があります. 中国語をサポートしていません. , 行と列はばかげて区別できません. 公式ドキュメントは古すぎるため、デモを構築するプロセスは非常に複雑になり、開発にはあまり適していません. 言及する価値があるのはこのコードだけです, これは本当に快適です.これは他のUIフレームワークに類を見ないものが多く、承認に値するものであり、今後このフレームワークやその後継フレームワークがこれらの問題を解決し、RustのUIがより強力になることを期待しています。
完全なコード
use iced::{
Alignment, button, Button, Column, Element, Length, Row, Sandbox, Settings, Text};
fn main() -> iced::Result {
Counter::run(Settings::default())
}
struct Counter {
value: i32,
// The local state of the two buttons
increment_button: button::State,
decrement_button: button::State,
}
#[derive(Debug, Clone, Copy)]
enum Message {
IncrementPressed,
DecrementPressed,
}
impl Sandbox for Counter {
type Message = Message;
fn new() -> Self {
Self {
value: 0, increment_button: Default::default(), decrement_button: Default::default() }
}
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(&mut self) -> Element<Message> {
Column::new().push(
Text::new("Counter")
).push(
Row::new().push(
Button::new(&mut self.increment_button, Text::new("+"))
.on_press(Message::IncrementPressed).width(Length::Fill),
).push(
Text::new(self.value.to_string()).size(22),
).push(
Button::new(&mut self.decrement_button, Text::new("-"))
.on_press(Message::DecrementPressed).width(Length::Fill),
)
)
.align_items(Alignment::Center).into()
}
}