【一緒にRustを学ぶ|フレームワーク|icedフレームワーク】rustネイティブのクロスプラットフォームGUIフレームワーク - iced


序文

プログラミング言語を学ぶためには、プログラミング言語の応用を決して放棄してはなりません。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_buttondecrement_button2 つのボタン + と - の状態を表します。

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()
    }
}


おすすめ

転載: blog.csdn.net/weixin_47754149/article/details/127271805