#events #winit #floem #loops #cross-platform #fork #unofficial

floem-winit

非官方 Floem 版本的 winit

1 个不稳定版本

0.29.4 2024年1月12日

#946 in GUI

Download history 224/week @ 2024-04-03 266/week @ 2024-04-10 337/week @ 2024-04-17 444/week @ 2024-04-24 447/week @ 2024-05-01 443/week @ 2024-05-08 444/week @ 2024-05-15 403/week @ 2024-05-22 557/week @ 2024-05-29 590/week @ 2024-06-05 469/week @ 2024-06-12 441/week @ 2024-06-19 418/week @ 2024-06-26 492/week @ 2024-07-03 571/week @ 2024-07-10 473/week @ 2024-07-17

2,014 每月下载量
6 个包 (2 直接) 中使用

Apache-2.0

2MB
42K SLoC

你可能正在寻找 真正的 winit 包

Floem 依赖于尚未上传到上游的 winit 变更。为了使 Floem 可在 crates.io 上发布,所有依赖项都必须在那里发布 - 因此这是一个非官方包。


lib.rs:

Winit 是一个跨平台的窗口创建和事件循环管理库。

构建窗口

在您能够构建一个 Window 之前,您首先需要构建一个 EventLoop。这可以通过 EventLoop::new() 函数完成。

use winit::event_loop::EventLoop;
let event_loop = EventLoop::new().unwrap();

完成此操作后,有两种方法可以创建一个 Window

第一种方法是最简单的,将为所有内容提供默认值。第二种方法允许您通过修改创建Window之前WindowBuilder对象的字段来自定义Window的外观和行为。

事件处理

一旦创建了一个Window,它将生成不同的事件。当发生某些输入事件时,例如光标在窗口上移动或在窗口聚焦时按键按下,Window对象可以生成WindowEvent。设备可以生成包含未过滤事件数据的DeviceEvent,这些数据不是特定于某个窗口的。一些用户活动,如鼠标移动,可以同时生成一个WindowEvent和一个DeviceEvent。如果需要,您还可以创建并处理自己的自定义Event::UserEvent

您可以通过调用EventLoop::run()来检索事件。此函数将为使用该特定EventLoop创建的每个Window分发事件,并运行直到使用exit(),此时将发出Event::LoopExiting

由于在某些平台(例如,Web、iOS)上无法正确实现,并且在大多数其他平台上表现不佳,Winit不再使用基于EventLoop::poll_events() -> impl Iterator<Event>的事件循环模型。然而,可以通过[^1]在一定程度上重新实现此模型。请参阅该方法的文档以获取更多关于为什么不鼓励使用此模型的原因,而不仅仅是因为兼容性的原因。

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

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

// ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
// dispatched any events. This is ideal for games and similar applications.
event_loop.set_control_flow(ControlFlow::Poll);

// ControlFlow::Wait pauses the event loop if no events are available to process.
// This is ideal for non-game applications that only update in response to user
// input, and uses significantly less power/CPU time than ControlFlow::Poll.
event_loop.set_control_flow(ControlFlow::Wait);

event_loop.run(move |event, elwt| {
    match event {
        Event::WindowEvent {
            event: WindowEvent::CloseRequested,
            ..
        } => {
            println!("The close button was pressed; stopping");
            elwt.exit();
        },
        Event::AboutToWait => {
            // Application update code.

            // Queue a RedrawRequested event.
            //
            // You only need to call this if you've determined that you need to redraw in
            // applications which do not always need to. Applications that redraw continuously
            // can render here instead.
            window.request_redraw();
        },
        Event::WindowEvent {
            event: WindowEvent::RedrawRequested,
            ..
        } => {
            // Redraw the application.
            //
            // It's preferable for applications that do not render continuously to render in
            // this event rather than in AboutToWait, since rendering in here allows
            // the program to gracefully handle redraws requested by the OS.
        },
        _ => ()
    }
});

WindowEvent有一个WindowId成员。在多窗口环境中,它应该与Window::id()返回的值进行比较,以确定哪个Window派发了事件。

在窗口上绘图

Winit不直接提供在Window上绘制的方法。但是,它允许您检索窗口的原始句柄和显示(请参阅platform模块和/或raw_window_handleraw_display_handle方法),这反过来又允许您创建一个OpenGL/Vulkan/DirectX/Metal等.上下文,可用于渲染图形。

请注意,如果应用程序在桌面合成器准备好向用户显示窗口之前没有向窗口渲染任何内容,许多平台将在窗口的客户区域显示垃圾数据。如果您注意到这种情况发生,您应该创建一个将 visible 设置为 false 的窗口,并且只有当您准备好向其渲染时才明确使其可见。

[^1]: EventLoopExtPumpEvents::pump_events() 仅在 Windows、macOS、Android、X11 和 Wayland 上可用。

依赖项

~0.3–21MB
~333K SLoC