とにかく書く

日々の雑感や知り得たことを、とにかく書いています

おっさんの挑戦(画像ビューア作成) 001

プログラマーという職業には、35歳定年説というのがある。

この時点で、非難轟々の方々もおられようが、私も35歳ころから、だんだん if 文を書くことに苦痛を感じ始めた。学生時代から打ち込んでいた分野で壁にぶつかって、深夜にジョニーウォーカー黒ラベルを一人傾けて、妙に鬱々としていた。ただのアル中だった。

そんなこんなあって、仕事が変わった。もはや前線兵士ではない。ジョニ黒もかつては高級酒だったが、いまではしがないサラリーマンでも買えてしまう。私も同じ。あぁ愛すべきジョニ黒。

新しい仕事では、画像をよく見る。最近の携帯電話は、PCで閲覧するには解像度が大きすぎるので、サイズを変更したい。おじさんはそんなに大きくなくていい。控えめでいい。だけど tiff も見たい。おじさんは欲張り。全部キーボードで操作したい。マウスとか何だか知らない画面タッチとか、口に出すのがちょっと恥ずかしい「スワイプ」とか、そういうのいらない。キーボードでいい。

ボケないためには、新しいことに挑戦するといいらしい。頭への刺激がボケ防止につながるとか。体を動かしながら(踊りながら)考えると(コーディングすると)なお一層効果がある。

そんなわけで、おじさんのはじめての Rust で画像ビューアーを作ってみることにした。
ここ2週間で The Book (第二版、日本語訳) の9章(エラー処理)まで読み進めた。1日1章。遅いけど、おじさんだし仕方ないね。

この時点でちょっと調べてみると、画像はimage クレートが使えそう。GUI は、ちょこちょこ見比べて iced が良さそう。

まず iced のドキュメント を参照にして、GUI 画面を出そうと思う。なにはともあれ、文字よりウィンドウが出たほうがババーンって感じで楽しい。

iced は、Elm の構造を参照にしているとのこと。Elm は 2012 年に修論として設計されたそうだ。最近過ぎて全然知らない。

ともあれ、ドキュメントをもとに根幹の概念を理解した。わかりやすい。

  • State : アプリケーションの状態
  • Messages : イベント(マウスクリックやキー押下など)
  • View Logic : State をどう画面表示するか
  • Update Logic : Messages に対する処理


で、ドキュメントにあるコード(カウンタ:ボタンを押すと画面の数字が増える)を実装した。
$ cargo run っと。
エラーが出た。

なんかエラーを見ると、確かにColumn型を返しているのに、その処置が正しくないようだ。よーわからんままいじっても、エラーが増えてよーわからん。そもそもクレートってなんだ?

クレートって、The Book のどこに載っていたかな?と見ると、10章じゃねーか。まだ9章までしか読んでねーよ。
まず10章を読みます。おっさんだししょうがないね。ジョニ黒おいしいね。

とりあえずエラーが出ているコード。よーわからんままいじった状態。

use iced::{button, executor, Application, Button, Column, Command, Settings, Text};

fn main() {
    Counter::run(Settings::default())
}

// State - the state of my application
#[derive(Debug, Clone, Copy)]
struct Counter {
    // The counter value
    value: i32,
    // The local state of the one buttons
    increment_button: button::State,
}

// Message - event that we care about
#[derive(Debug, Clone, Copy)]
pub enum Message {
    IncrementPressed,
}

impl Application for Counter {
    // Use default
    type Executor = executor::Default;
    type Message = Message;
    type Flags = ();
    fn new(_flags: ()) -> (Counter, Command<Message>) {
        (Counter::default(), Command::none())
    }

    // View Logic
    fn view(&mut self) -> Counter<Message> {
        // Use a column: a simple vertical layout
        Column::new()
            .push(
                // The increment button.
                // The event IncrementPressed is launched when it is pressed
                Button::new(&mut self.increment_button, Text::new("+"))
                    .on_press(Message::IncrementPressed),
            )
            .push(
                // The message
                Text::new(self.value.to_string()).size(50),
            )
    }
    // Update logic: connect events to functions
    fn update(&mut self, message: Message) {
        match message {
            Message::IncrementPressed => {
                self.value += 1;
            }
        }
    }

    fn title(&self) -> String {
        String::from("kilo")
    }
}