#窗口创建 #事件 #winit #winit-窗口 #跨平台 #窗口事件 #窗口管理

luminvent_winit

跨平台窗口创建库

2 个不稳定版本

0.27.6-alpha2023年4月20日
0.26.1 2022年4月20日

#311 in GUI

Download history 10/week @ 2024-03-08 26/week @ 2024-03-15 21/week @ 2024-03-22 81/week @ 2024-03-29 33/week @ 2024-04-05 2/week @ 2024-04-12 11/week @ 2024-04-26 1/week @ 2024-05-03 1/week @ 2024-05-10 30/week @ 2024-05-17 119/week @ 2024-05-24 5/week @ 2024-05-31 2/week @ 2024-06-07 33/week @ 2024-06-14 6/week @ 2024-06-21

56 每月下载量

Apache-2.0

1.5MB
31K SLoC

winit - Rust 中的跨平台窗口创建和管理

Crates.io Docs.rs CI Status

[dependencies]
winit = "0.27.5"

文档

有关 winit 作用域内的功能,请参阅 FEATURES.md

有关 winit 作用域之外的功能,请参阅维基中的 其他 crates 提供的功能缺失

联系我们

加入我们以下任一方式

Matrix Libera.Chat

使用方法

Winit 是一个窗口创建和管理库。它可以创建窗口并允许您处理由窗口产生的事件(例如:窗口大小调整、按键被按下、鼠标移动等)。

Winit 被设计成库层次结构中的底层砖块。因此,为了在窗口上显示内容,您需要使用 winit 提供的平台特定获取器,或另一个库。

use winit::{
    event::{Event, WindowEvent},
    event_loop::{ControlFlow, EventLoop},
    window::WindowBuilder,
};

fn main() {
    let event_loop = EventLoop::new();
    let window = WindowBuilder::new().build(&event_loop).unwrap();

    event_loop.run(move |event, _, control_flow| {
        *control_flow = ControlFlow::Wait;

        match event {
            Event::WindowEvent {
                event: WindowEvent::CloseRequested,
                window_id,
            } if window_id == window.id() => *control_flow = ControlFlow::Exit,
            _ => (),
        }
    });
}

Winit 只官方支持 Rust 编译器的最新稳定版本。

Cargo 功能

Winit 提供以下功能,您可以在您的 Cargo.toml 文件中启用它们

  • serde: 启用使用 Serde 的某些类型的序列化/反序列化。
  • x11(默认启用):在 Unix 平台上,使用 X11 后端编译
  • wayland(默认启用):在 Unix 平台上,使用 Wayland 后端编译
  • mint: 启用 mint(数学互操作性标准类型)转换。

平台特定用法

Wayland

请注意,在您对窗口进行绘制/显示之前,Wayland 上的窗口不会显示。

winit 不执行绘制,请尝试 glutin 中的示例。

WebAssembly

要运行 Web 示例:cargo run-wasm --example web

Winit 支持使用 web-sys 将代码编译为 wasm32-unknown-unknown 目标。

在网页平台上,Winit窗口由一个<canvas>元素支持。您可以选择向Winit提供一个<canvas>元素,或者让Winit创建一个<canvas>元素,然后您可以检索并自行将其插入DOM中

有关使用Winit和WebAssembly的示例代码,请查看网页示例。有关在WebAssembly上使用Rust的信息,请查看Rust和WebAssembly书籍

Android

Android后端基于(并公开了类型)ndk存储库。

原生的Android应用需要某种形式的“胶水”存储库,该存储库负责定义您的Rust应用程序的主入口点以及跟踪各种生命周期事件并与主JVM线程同步。

Winit使用android-activity作为胶水存储库(在0.28之前,它使用了ndk-glue)。

您应用程序所依赖的胶水存储库版本必须与Winit所依赖的版本匹配,因为胶水存储库负责您应用程序的主入口点。如果Cargo解析多个版本,它们将发生冲突。

winit胶水兼容性表

winit ndk-glue
0.28 android-activity= "0.4"
0.27 ndk-glue= "0.7"
0.26 ndk-glue= "0.5"
0.25 ndk-glue= "0.3"
0.24 ndk-glue= "0.2"

避免胶水版本冲突的推荐方法是避免显式依赖android-activity存储库,而是使用Winit在winit::platform::android::activity::*下重新导出的API

在Android设备上运行需要一个动态系统库,将其添加到Cargo.toml中

[lib]
name = "main"
crate-type = ["cdylib"]

所有Android应用程序都基于一个Activity子类,而android-activity存储库旨在支持对此基类的不同选择。您的应用程序必须通过特性标志指定它需要的基类

基类 特性标志 说明
NativeActivity android-native-activity 内置在Android中 - 您可以在不编译任何Java或Kotlin代码的情况下使用它。可能需要Java或Kotlin代码来子类化NativeActivity以访问某些平台功能。它不继承自AndroidAppCompat基类。
GameActivity android-game-activity 继承自AndroidAppCompat,这是一个事实上的标准Activity基类,有助于支持更广泛的Android版本。需要能够编译Java或Kotlin并从Maven仓库(或链接到一个嵌入的发布版GameActivity)的构建系统。

例如,将以下内容添加到Cargo.toml中:

winit = { version = "0.28", features = [ "android-native-activity" ] }

[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.11.0"

例如,定义库的入口点如下:

#[cfg(target_os = "android")]
use winit::platform::android::activity::AndroidApp;

#[cfg(target_os = "android")]
#[no_mangle]
fn android_main(app: AndroidApp) {
    use winit::platform::android::EventLoopBuilderExtAndroid;

    android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Trace));

    let event_loop = EventLoopBuilder::with_user_event()
        .with_android_app(app)
        .build();
    _main(event_loop);
}

有关更多详细信息,请参阅这些 android-activity 示例应用程序

ndk-glue 转换到 android-activity

如果您的应用程序目前基于通过 ndk-glue crate 的 NativeActivity,并使用 cargo apk 构建,那么所需的最小更改如下:

  1. 从您的 Cargo.toml 中移除 ndk-glue
  2. 为 Winit 启用 "android-native-activity" 功能: winit = { version = "0.28", features = [ "android-native-activity" ] }
  3. 添加一个 android_main 入口点(如上所示),而不是使用来自 ndk-macros 的 '[ndk_glue::main] proc 宏(可选添加对 android_logger 的依赖,并初始化日志,如上所示)。
  4. 在构建事件循环时,将应用程序收到的 AndroidApp 的克隆传递给 Winit(如上所示)。

MacOS

许多功能都期望在您开始做任何事情之前,应用程序已经准备好;这包括创建窗口、获取监视器、绘制等,请参阅问题 #2238#2051#2087

如果您遇到问题,您应该在 Event::NewEvents(StartCause::Init) 中执行您的初始化。

iOS

与 macOS 类似,iOS 的主 UIApplicationMain 执行一些所有 UI 相关代码所需的基本初始化工作,请参阅问题 #1705。您应该在 Event::NewEvents(StartCause::Init) 内创建窗口。

依赖项

~0.2–17MB
~233K SLoC