0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rust】winitを使ってウインドウ作成

0
Posted at

はじめに

今までC++でコードを書いてきましたが、「Rustも触ってみたい!」ということで、今回はRustのwinitを使ってウインドウを作成していきたいと思います。

この記事では、C++経験者の視点から「Rustではこう書くのか」という点も交えながら解説していきます。


Cargo.tomlにwinitを追加

Rustでは、使用するライブラリをCargo.tomlに記述します。

C++でいうライブラリの追加に近いイメージです。

[package]
name = "RustEngine"
version = "0.1.0"
edition = "2024"

[dependencies]
winit = "0.30"

use宣言

まずは必要な型や関数をuseで読み込みます。

use winit::{
    application::ApplicationHandler,
    dpi::PhysicalSize,
    event::WindowEvent,
    event_loop::{ActiveEventLoop, EventLoop},
    window::{Window, WindowId},
};

useは、C++のusing宣言に近い機能です。

モジュール内にある型や関数を現在のスコープで利用できるようにしています。


アプリケーションクラス(構造体)の定義

RustにはC++のようなクラスという構文はありません。

その代わりに、

  • struct
  • impl
  • trait

を組み合わせることで、クラスに近いことができます。

まずはアプリケーションを表す構造体を作成します。

#[derive(Default)]
struct App {
    window: Option<Window>,
}

struct AppはC++でいうstructに近いものです。

その中に

window: Option<Window>,

というメンバ変数を持っています。

Option<T>は、C++のstd::optional<T>とほぼ同じで、

  • Some(T)・・・値がある
  • None・・・値がない

のどちらかを保持できます。

今回はまだウインドウを作成していないため、最初はNoneになります。


#[derive(Default)]とは?

#[derive(Default)]は、Defaultトレイトを自動実装するための属性です。

例えば、

let app = App::default();

と書けるようになります。

実際には、以下のようなコードが自動生成されるイメージです。

impl Default for App {
    fn default() -> Self {
        Self {
            window: None,
        }
    }
}

つまり、

let app = App::default();

を実行すると、

App {
    window: None,
}

という状態で生成されます。


ApplicationHandlerの実装

続いて、ApplicationHandlerトレイトを実装します。

impl ApplicationHandler for App {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        let attrs = Window::default_attributes()
            .with_title("RustEngine")
            .with_inner_size(PhysicalSize::new(1280, 720));

        self.window = Some(event_loop.create_window(attrs).unwrap());
    }

    fn window_event(
        &mut self,
        event_loop: &ActiveEventLoop,
        _window_id: WindowId,
        event: WindowEvent,
    ) {
        match event {
            WindowEvent::CloseRequested => {
                event_loop.exit();
            }
            _ => {}
        }
    }
}
impl ApplicationHandler for App

は、App型にApplicationHandlerトレイトを実装しているという意味です。

C++でいうインターフェースを実装するようなイメージが一番近いと思います。


resumed()

fn resumed(&mut self, event_loop: &ActiveEventLoop) {
    let attrs = Window::default_attributes()
        .with_title("RustEngine")
        .with_inner_size(PhysicalSize::new(1280, 720));

    self.window = Some(event_loop.create_window(attrs).unwrap());
}

ここでウインドウを作成しています。

まず、

Window::default_attributes()

でウインドウの設定を作成し、

event_loop.create_window(attrs)

へ渡して実際にウインドウを生成しています。

生成されたWindow

Some(...)

としてwindowへ保存しています。

なお、winit 0.30ではウインドウはresumed()内で生成するのが基本となっています。


window_event()

fn window_event(
    &mut self,
    event_loop: &ActiveEventLoop,
    _window_id: WindowId,
    event: WindowEvent,
) {
    match event {
        WindowEvent::CloseRequested => {
            event_loop.exit();
        }
        _ => {}
    }
}

こちらはウインドウに関するイベント処理です。

Rustではswitch文の代わりにmatchを使います。

今回は、

WindowEvent::CloseRequested

つまり、ウインドウの閉じるボタンが押されたときだけ処理を書いています。

event_loop.exit();

を呼ぶことでイベントループを終了し、アプリケーションも終了します。


アプリケーションの実行

最後にmain関数です。

fn main() {
    let event_loop = EventLoop::new().unwrap();

    let mut app = App::default();

    event_loop.run_app(&mut app).unwrap();
}

ここで少し流れを整理してみます。

まず、

let mut app = App::default();

を実行した時点では、

App
└── window = None

という状態です。

その後、

event_loop.run_app(&mut app)

を呼ぶことでイベントループが開始されます。

イベントループ開始後、winitが内部でresumed()を呼び出します。

すると、

self.window = Some(event_loop.create_window(attrs).unwrap());

が実行され、

App
└── window = Some(Window)

となり、実際のウインドウが生成されます。

処理の流れを図にすると次のようになります。

App::default()
        │
        ▼
window = None
        │
        ▼
run_app()
        │
        ▼
resumed() が呼ばれる
        │
        ▼
create_window()
        │
        ▼
window = Some(Window)
        │
        ▼
イベントループ開始

おわりに

今回はRustのwinitを使って、ウインドウを作成してみました。

C++を書いてきた身としては、最初は

  • クラスがない
  • Option
  • trait
  • impl

など、戸惑うことがたくさんありました。

しかし、実際に触ってみると「Rustではこういう考え方なんだな」と少しずつ理解できるようになってきました。

まだまだ勉強することは多いですが、Rustの所有権やトレイトなどをしっかり理解できれば、とても強力な言語だと感じています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?