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 进行模式匹配来处理数据的多种状况. 先这样吧.

相关文章
相关标签/搜索