0x02. 處理窗口關閉

上一篇已經使用 sdl2 顯示了一個窗口, 咱們當時的作法是讓線程休眠 10 秒看了個窗口的樣子, 如今咱們想讓這個窗口經過咱們主動觸發事件來關閉, 其餘正常狀況下一直運行.git

開始以前先建立個分支, git checkout -b eventsgithub

讓窗口一直顯示

讓窗口一直顯示很好辦, 在原先代碼基礎上, 經過一個死循環就能解決.正則表達式

use sdl2::pixels::Color;

fn main() {
    let sdl2_context = sdl2::init().unwrap();
    let video = sdl2_context.video().unwrap();
    let window = video
        .window("Arcade Shooter", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();
    let mut canvas = window.renderer().accelerated().build().unwrap();
    canvas.set_draw_color(Color::RGB(0, 0, 0));
    canvas.clear();
    canvas.present();
    'running: loop {}
}
複製代碼

Rust 有一個 loop 的循環方式, 'running 能夠不用理會只是個生命週期標記. 如今這個程序所處的狀態算不上一個正常的狀態, 以後要讓程序能夠受用戶控制關閉.canvas

讓窗口能夠關閉

rust-sdl2 的事件控制方法在其 github 倉庫 examples 中有, 就這個樣子, 經過調用 sdl2_contextevent_pump 函數獲取 sdl2 的事件集, 再在循環中遍歷經過事件集的 poll_iter 函數獲取到的輪詢迭代器ide

let mut event_pump = sdl2_context.event_pump().unwrap();
'running: loop {
    for event in event_pump.poll_iter() {
        match event {
            Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                break 'running
            },
            _ => {}
        }
    }
}
複製代碼

咱們要處理的事件是程序 Quit 事件和按了鍵盤的 escape 的事件, 如今來建立個文件, 就叫 events.rs, 放到 main.rs 同級目錄下函數

use sdl2::EventPump;

pub struct Events {
    pump: EventPump,
    pub quit: bool,
    pub key_escape: bool,
}

impl Events {
    pub fn new(pump: EventPump) -> Self {
        Self {
            pump,
            quit: false,
            key_escape: false,
        }
    }
    pub fn pump(&mut self) {
        for event in self.pump.poll_iter() {
            use sdl2::event::Event::*;
            use sdl2::keyboard::Keycode::*;
            match event {
                Quit { .. } => self.quit = true,
                KeyDown {
                    keycode: Some(Escape),
                    ..
                } => self.key_escape = true,
                _ => {}
            }
        }
    }
}
複製代碼

如今能夠看到一個 Events 的結構體, Rust 結構體目前先理解成其餘語言的 class, 咱們能夠給一個 class 定義屬性, 還能夠添加構造方法, 通常的方法, 還能夠經過 private, public, protected 這類關鍵字控制屬性的訪問權限, Rust 結構體也具有這類特性, 不過有點區別的是, 沒有 protected 方面的控制. Rust 結構體沒有嚴格命名的構造方法, 根據慣例是使用 new, 只要本身須要, 也可使用 create, foo, bar ... 之類的函數做爲構造方法.
Rust 一個很是好使的語法就是模式匹配, 比 Apple 每一年出的新語言模式匹配更容易玩. 功能強大, match 後面接一堆正則表達式均可以, 要啥自行車.oop

如今結構體定義了 quit, key_escape 這些用來標註狀態修改的 bool 類型屬性, 而 pump 屬性是用來給內部的函數使用的, 不使用 pub 關鍵字來開放外部使用. 咱們看到 pump 函數有個 self 的參數, 這個參數能夠理解成表明結構體實例自己, 有了這個參數, 能夠在結構體實例調用本函數時, 經過 self 使用實例自身的屬性, 因爲咱們將準備在該函數內修改實例自身的屬性值, 因此使用 mut 來達到可變的效果. 至於 & 這個符號, 若是想讓實例調用 pump 函數後還能繼續使用, 得使用借用的方式傳 self.ui

而後在 main.rs 中使用一下咱們的事件處理器spa

#![feature(uniform_paths)]

use sdl2::pixels::Color;
mod events;
use events::Events;

fn main() {
    let sdl2_context = sdl2::init().unwrap();
    let video = sdl2_context.video().unwrap();
    let window = video
        .window("Arcade Shooter", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();
    let mut canvas = window.renderer().accelerated().build().unwrap();
    canvas.set_draw_color(Color::RGB(0, 0, 0));
    canvas.clear();
    canvas.present();
    let mut event = Events::new(sdl2_context.event_pump().unwrap());

    'running: loop {
        event.pump();
        if event.quit || event.key_escape { break 'running; }
    }
}
複製代碼

#![feature(uniform_paths)] 這一段是用來使用 Rust 的新特性, 由於我想簡單點使用咱們的 events 模塊, 以後就能夠直接在 main 函數內使用 Events 結構體了.線程

後面的邏輯很簡單, 每次在循環中調用一下 event.pump 來根據觸發的事件修改狀態, 判斷是否中止循環.


這一篇咱們使用一個帶標記的 loop 循環讓程序持續可用. 經過一個結構體, 使用 impl Foo 的方式給結構體添加函數, 瞭解到函數能夠經過 self 使用實例自身. 咱們還能使用 match 進行模式匹配來處理數據的多種狀況. 先這樣吧.

相關文章
相關標籤/搜索