开始冒险的第一步,整个窗口出来
初始化一个项目
首先我们使用 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
会有一个窗口弹出
我的大概是这个效果
通常情况下运行会得到一个白色或者黑色的窗口,甚至在某些情况下窗口里会出现你正在打开的程序的一部分的图像 这都是正常的现象