开始冒险的第一步,整个窗口出来

初始化一个项目

首先我们使用 cargo init try 创建一个基础的Rust项目

try
    src
    cargo.toml
    .git

大概是这个样子的

我们需要安装一些库. Rust是一个非常好的工具因为他提供了Cargo这么好用的减少心智负担的工具 我们打开 cargo.toml

[package] 
#这个一般都给你写好了,不用操心
name = "try" 
#项目名称
version = "0.1.0" 
#项目版本
authors = ["lemonhx <runzhe2001@hotmail.com>"] 
#作者们
edition = "2018"

[dependencies] 
#依赖的库
winit = "0.19"
#我们核心的GFX硬件抽象库
gfx-hal = "0.3.0"
#一个玩过rust就知道的库
arrayvec = "0.4"

#vulkan作为gfx后端的配置
[dependencies.gfx-backend-vulkan]
version = "0.3"
features = ["winit"]
optional = true

#metal作为gfx后端的配置
[target.'cfg(target_os = "macos")'.dependencies.gfx-backend-metal]
version = "0.3"
features = ["winit"]
optional = true

#DX12作为gfx后端的配置
[target.'cfg(windows)'.dependencies.gfx-backend-dx12]
version = "0.3.0"
features = ["winit"]
optional = true

#编译配置
[build-dependencies]
glsl-to-spirv = "0.1.7"

#启用扩展,我们默认使用跨平台的Vulkan
[features]
default = ["gfx-backend-vulkan"]
metal = ["gfx-backend-metal"]
dx12 = ["gfx-backend-dx12"]
vulkan = ["gfx-backend-vulkan"]

抄好之后使用cargo run下载依赖并运行,不出问题的话就会有hello world窗口弹出

窗口结构

我们需要定义以下窗口结构体

pub struct WindowState {
  pub evloop: EventsLoop,
  pub window: Window,
}

这是我定义的一个窗口结构体,里面装有一个事件循环和一个窗口

事件循环是什么可能很多人不知道我可以大概解释一下:

我自己在跑步(循环),跑着跑着被绊倒了(遇到事件),我爬起来(事件的处理方式),我继续跑(重新回到循环)

这个是一个简单的事件循环,同样,我还可以

跑步(循环),被车撞了(遇到事件),躺地上求救(事件处理),没人搭理死了(处理结果)

很简单明了,创建窗口需要绑定一个事件循环的原因是,你可能对着这个窗口按键,点击鼠标,拖拽,窗口会用你之前定义好的事件处理方式去处理这些事件.

然后如何初始化一个对应这个窗口的实例呢?

impl WindowState {
  //为了避免使代码过度复杂,这里就直接不行报错了
  pub fn new<T: Into<String>>(title: T, size: (f64, f64)) -> Self{
    let evloop = EventsLoop::new(); //创建事件循环
    let window = match WindowBuilder::new() //使用窗口创造器
      .with_title(title)  //绑上标题
      .with_dimensions(LogicalSize::new(size.0, size.1)) //设置大小
      .build(&evloop)  //尝试构造 这里的返回类型是一个Result所以我们再match一手
    {
      Ok(x) => x,
      Err(e) => {println!("创建窗口失败,原因:{:?}", e);panic!()}
    };
    Self {
      evloop,
      window,
    }
  }
}

事件处理()

一个窗口对应了一个事件循环,有些时候事件循环就是一个while循环,但是这里我们的winit库给我们提供了一个基于control flow的一个事件循环,总体来讲就是我们不需要把事件的处理方法挤在一个while里面来写了,在这里我定义了一个事件处理函数

use winit::{ControlFlow, Event, VirtualKeyCode, WindowEvent};// 使用 控制流 事件 按键代码 窗口事件
// 这个函数收到一个事件,返回一个控制流(之后干什么)
pub fn event_handler(event: Event) -> winit::ControlFlow {
    match event {
        // 处理键盘输入事件
        Event::WindowEvent { event, .. } => match event {
            WindowEvent::KeyboardInput { input, .. } => {
                if let Some(VirtualKeyCode::Escape) =  input.virtual_keycode {//如果是ESC被按下来了
                    ControlFlow::Break //退出事件循环
                } else {
                    ControlFlow::Continue //要不啥也不干
                }
            }
            WindowEvent::CloseRequested => ControlFlow::Break, //如果窗口被关了,退出程序

            _ => ControlFlow::Continue,
        },
        _ => ControlFlow::Continue,
    }
}

把上面的拼装到一起

最后开始写app.rs 我们的app暂时仅仅只有一个窗口,所以我们创建一个结构体包含一个窗口实例就行了

use super::super::window::window::*;
use super::super::event_handler::event_handler::*;
pub struct App {
    windowstate : WindowState
}
impl App {
    pub fn new() {
        let mut ws = WindowState::new("new_window", (1024f64, 768f64)); //设置窗口标题和大小
        ws.evloop.run_forever(event_handler); //开始运行事件循环
    }
}

yes! 开始运行

最后,我们更改main.rs

pub mod app;
pub mod window;
pub mod event_handler;

use app::app::*;

fn main() {
  let _ = App::new();
}

最后cargo run会有一个窗口弹出

我的大概是这个效果 来自ubuntu + dde

通常情况下运行会得到一个白色或者黑色的窗口,甚至在某些情况下窗口里会出现你正在打开的程序的一部分的图像 这都是正常的现象

results matching ""

    No results matching ""