Rust: Native Windows GUI下载、安装、演示入门

2023-05-16

上 github 下载,网址为 https://github.com/gabdube/native-windows-gui。

上面有安装说明。按说明方法,老是提示权限不够。配置了 ssh 公钥证书,仍然不行。请教同事后得知,可能是网络传输问题,在国内访问github经常会出现这类问题。于是想办法通过其他方法下载了压缩包。具体用法如下:

Native Windows GUI

欢迎使用 Native Windows GUI(又名NWG)。用于在 Microsoft Windows 桌面上开发本机 GUI 应用程序的 rust 库。

NWG 是 WINAPI 上的轻量级封装。它允许开发人员通过提供一个简单、安全和 Rust风格的接口来处理形形色色的 API 调用。Native Windows GUI 大大简化了开发工作,这意味着更少的编译时间、最少的资源使用、更少的文档搜索时间和更多的应用程序开发时间。

这是 NWG 的第三个也是最后一个版本。它被认为是“成熟的”。这个版本几乎实现了在Windows上开发应用程序所需的所有功能。不要费心使用旧版本,因为它们有“不可调和的设计决策”,并且不能支持一些关键功能。未来的发展将在其他代码库进行。

安装

如果你打算在自己的项目中使用 NWG,需要先把它添加到 cargo.toml 文件中。

[dependencies]
native-windows-gui = "1.0.12"
native-windows-derive = "1.0.3" # Optional. Only if the derive macro is used.

And then, in main.rs or lib.rs :
然后,在 main.rs 或者 lib.rs 文件中添加一下声明:

extern crate native_windows_gui as nwg;
extern crate native_windows_derive as nwd;  // Optional. Only if the derive macro is used.

Rust 2018 aliasing

通过在 Cargo 中添加以下代码,可以跳过源代码中的 extern crate 定义。toml 注意到,过程宏仍然需要 extern crate 定义,因此这不适用于native-windows-derive。

[dependencies]
nwg = {version = "^1.0.12", package = "native-windows-gui"}

尝试一下

你自己看看吧。NWG 有大量的示例和一个完全交互式的测试套件。您唯一需要做的是:

git clone git@github.com:gabdube/native-windows-gui.git

说明:上面这条指令我无论如何都无法执行。尽管成功设置了 ssh 公钥,也无法成功执行此指令。最终请同时帮我从其他途径下载到此套件源代码。

cd native-windows-gui/native-windows-gui # Running the tests from the workspace screws up the features

cargo test everything --features "all"  # For the test suite
cargo run --example basic
cargo run --example calculator
cargo run --example message_bank
cargo run --example image_decoder_d --features "extern-canvas"
cargo run --example partials --features "listbox frame combobox"
cargo run --example system_tray --features "tray-notification message-window menu cursor"
cargo run --example dialog_multithreading_d --features "notice"
cargo run --example image_decoder_d --features "image-decoder file-dialog"
cargo run --example month_name_d --features "winnls textbox"
cargo run --example splash_screen_d --features "image-decoder"
cargo run --example drop_files_d --features "textbox"

cd examples/opengl_canvas
cargo run

运行上面的命令,各种各样的例子,应有尽有了,效果非常好!注意执行命令的时候,不要复制 # 号和后面的注释。里面显示 image 图像的例子和最后 OpenGL 的图形展示,是我比较感兴趣的功能。

示例中最接近实际应用程序的内容

cd ../examples/sync-draw
cargo run

这个例子展示了一个简单的画图功能,可以用画笔画图,也可以用橡皮檫檫除绘制内容。

由于嵌入资源,要求控制台以管理员身份运行

cd ../examples/embed_resources
cargo run

从 Ubuntu 系统进行交叉编译

要求安装: MinGW 编译器。

sudo apt install gcc-mingw-w64-x86-64

要求: Rust 支持

rustup target add x86_64-pc-windows-gnu

编译并运行基本例程:

cargo build --release --target=x86_64-pc-windows-gnu
cargo build --release --target=x86_64-pc-windows-gnu --example basic
wine target/x86_64-pc-windows-gnu/release/examples/basic.exe

项目结构

这是git的主要项目。它分为多个部分

  • native-windows-gui
    • 基本库。包括交互式测试套件和大量示例
  • native-windows-derive
    • 一个程序宏,它从rust结构生成GUI应用程序(在我看来很酷)
  • docs/native-windows-docs 文档联机阅读
    • 大量文档,涵盖了您需要了解的有关NWG的所有信息
  • showcase
    • 示例的图像。如果你已经制作了一个NWG应用程序,并想在这里共享它,请给我发一条消息或打开一个PR。这里免费提供场所。

支持的功能

  • 整个winapi控件库(参考)
    • 一些非常特殊的控件不受支持:平面滚动条、ip控件、钢筋和寻呼机。
  • 菜单和菜单栏
  • 图像和字体资源
    • BMP
    • ICO
    • CUR
    • PNG*
    • GIF*
    • JPG*
    • TIFF*
    • DDS*
    • *: Extended image formats with the Windows Imaging Component (WIC).
  • 本地化支持
    • 在内部使用Windows国家语言支持(参考)
  • 工具提示
  • 系统托盘通知
  • 光标处理
  • 完整的剪贴板包装
  • 部分模板支持
    • 将大型应用程序拆分为块
  • 动态控件支持
    • 在运行时添加/删除控件
    • 在运行时绑定或取消绑定新事件
  • 多线程应用程序支持
    • 从另一个线程与GUI线程通信
    • 在不同线程上运行多个窗口
  • 简单布局配置
    • Flexbox布局
    • 网格布局
  • 拖放
    • 将文件从桌面拖放到窗口
  • 最常见的对话框
    • 文件对话框(保存、打开、打开文件夹)
    • “字体”对话框
    • “颜色”对话框
  • 可由外部渲染API使用的画布
  • 高DPI感知
  • 支持辅助功能
    • 选项卡导航
  • 支持低级系统消息捕获(HWND、MSG、WPARAM、LPARAM)
  • 使用Wine和mingw从Linux到Windows的交叉编译和测试。
    • 并非所有功能都支持(但大多数都支持,谢谢WINE!)
    • 参见 https://zork.net/~st/jottings/rust-windows-and-debian.html l以获取要遵循的步骤

性能

这是在3.40GHz、3401 Mhz、4核、8逻辑处理器的Intel(R)Core(TM)i7-3770 CPU上测量的
在 release 模式下,基本示例的磁盘容量为163kb,内存为900kb。运行时间是瞬时的。
交互式测试套件(包含所有功能和100个测试)的磁盘容量为931kb,内存为8MB。运行时间仍然是瞬时的。
基本应用程序的初始构建时间约为22秒。这主要是由于 winapi 的初始编译时间。随后的编译时间约为0.7秒。

开发

这个图书馆的开发被认为是“完成了”。我的意思是,API不会有任何更改。如果发现错误或文档中的某些区域不清楚,可能会引发问题。如果我忽略了一个非常重要的特性,那么很可能会添加它。

授权许可

NWG使用MIT许可证。

如果说存在“屎上最宽松”的协议,那肯定就是 MIT 协议了!因为它允许你毫无节操地使用开源代码,你可以修改、闭源、商业化等等,MIT只提了两点要求:

  • 你使用的时候要保留 MIT 许可声明。
    我觉得这个要求不过分,你免费用了人家的东西,产品发行的时候给人家挂个名表示一下感谢总不过分吧?
  • 出了问题别找作者的麻烦。
    这个要求也合情合理。人家没挣你的钱,开源代码是你自己自愿使用的,没人强迫你。如果因为开源代码造成了重大经济损失,你也别找人家赔偿。这个是一个愿打、一个愿挨,都是自己情愿的。

代码例子

With native windows derive

#![windows_subsystem = "windows"]
/*!
    A very simple application that shows your name in a message box.
    Unlike `basic_d`, this example uses layout to position the controls in the window
*/


extern crate native_windows_gui as nwg;
extern crate native_windows_derive as nwd;

use nwd::NwgUi;
use nwg::NativeUi;


#[derive(Default, NwgUi)]
pub struct BasicApp {
    #[nwg_control(size: (300, 115), position: (300, 300), title: "Basic example", flags: "WINDOW|VISIBLE")]
    #[nwg_events( OnWindowClose: [BasicApp::say_goodbye] )]
    window: nwg::Window,

    #[nwg_layout(parent: window, spacing: 1)]
    grid: nwg::GridLayout,

    #[nwg_control(text: "Heisenberg", focus: true)]
    #[nwg_layout_item(layout: grid, row: 0, col: 0)]
    name_edit: nwg::TextInput,

    #[nwg_control(text: "Say my name")]
    #[nwg_layout_item(layout: grid, col: 0, row: 1, row_span: 2)]
    #[nwg_events( OnButtonClick: [BasicApp::say_hello] )]
    hello_button: nwg::Button
}

impl BasicApp {

    fn say_hello(&self) {
        nwg::modal_info_message(&self.window, "Hello", &format!("Hello {}", self.name_edit.text()));
    }
    
    fn say_goodbye(&self) {
        nwg::modal_info_message(&self.window, "Goodbye", &format!("Goodbye {}", self.name_edit.text()));
        nwg::stop_thread_dispatch();
    }

}

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");
    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");
    let _app = BasicApp::build_ui(Default::default()).expect("Failed to build UI");
    nwg::dispatch_thread_events();
}

简单例子,适用于只需要简单静态UI的情况

#![windows_subsystem = "windows"]
/**
    A very simple application that show your name in a message box.

    This demo shows how to use NWG without the NativeUi trait boilerplate.
    Note that this way of doing things is alot less extensible and cannot make use of native windows derive.

    See `basic` for the NativeUi version and `basic_d` for the derive version
*/
extern crate native_windows_gui as nwg;
use std::rc::Rc;

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");
    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");

    let mut window = Default::default();
    let mut name_edit = Default::default();
    let mut hello_button = Default::default();
    let layout = Default::default();

    nwg::Window::builder()
        .size((300, 115))
        .position((300, 300))
        .title("Basic example")
        .build(&mut window)
        .unwrap();

    nwg::TextInput::builder()
        .text("Heisenberg")
        .focus(true)
        .parent(&window)
        .build(&mut name_edit)
        .unwrap();

    nwg::Button::builder()
        .text("Say my name")
        .parent(&window)
        .build(&mut hello_button)
        .unwrap();

    nwg::GridLayout::builder()
        .parent(&window)
        .spacing(1)
        .child(0, 0, &name_edit)
        .child_item(nwg::GridLayoutItem::new(&hello_button, 0, 1, 1, 2))
        .build(&layout)
        .unwrap();

    let window = Rc::new(window);
    let events_window = window.clone();

    let handler = nwg::full_bind_event_handler(&window.handle, move |evt, _evt_data, handle| {
        use nwg::Event as E;

        match evt {
            E::OnWindowClose => 
                if &handle == &events_window as &nwg::Window {
                    nwg::modal_info_message(&events_window.handle, "Goodbye", &format!("Goodbye {}", name_edit.text()));
                    nwg::stop_thread_dispatch();
                },
            E::OnButtonClick => 
                if &handle == &hello_button {
                    nwg::modal_info_message(&events_window.handle, "Hello", &format!("Hello {}", name_edit.text()));
                },
            _ => {}
        }
    });

    nwg::dispatch_thread_events();
    nwg::unbind_event_handler(&handler);
}

使用NativeUi样板文件

#![windows_subsystem = "windows"]
/*!
    A very simple application that shows your name in a message box.
    Uses layouts to position the controls in the window
*/

extern crate native_windows_gui as nwg;
use nwg::NativeUi;


#[derive(Default)]
pub struct BasicApp {
    window: nwg::Window,
    layout: nwg::GridLayout,
    name_edit: nwg::TextInput,
    hello_button: nwg::Button
}

impl BasicApp {

    fn say_hello(&self) {
        nwg::modal_info_message(&self.window, "Hello", &format!("Hello {}", self.name_edit.text()));
    }
    
    fn say_goodbye(&self) {
        nwg::modal_info_message(&self.window, "Goodbye", &format!("Goodbye {}", self.name_edit.text()));
        nwg::stop_thread_dispatch();
    }

}

//
// ALL of this stuff is handled by native-windows-derive
//
mod basic_app_ui {
    use native_windows_gui as nwg;
    use super::*;
    use std::rc::Rc;
    use std::cell::RefCell;
    use std::ops::Deref;

    pub struct BasicAppUi {
        inner: Rc<BasicApp>,
        default_handler: RefCell<Option<nwg::EventHandler>>
    }

    impl nwg::NativeUi<BasicAppUi> for BasicApp {
        fn build_ui(mut data: BasicApp) -> Result<BasicAppUi, nwg::NwgError> {
            use nwg::Event as E;
            
            // Controls
            nwg::Window::builder()
                .flags(nwg::WindowFlags::WINDOW | nwg::WindowFlags::VISIBLE)
                .size((300, 115))
                .position((300, 300))
                .title("Basic example")
                .build(&mut data.window)?;

            nwg::TextInput::builder()
                .text("Heisenberg")
                .parent(&data.window)
                .focus(true)
                .build(&mut data.name_edit)?;

            nwg::Button::builder()
                .text("Say my name")
                .parent(&data.window)
                .build(&mut data.hello_button)?;

            // Wrap-up
            let ui = BasicAppUi {
                inner: Rc::new(data),
                default_handler: Default::default(),
            };

            // Events
            let evt_ui = Rc::downgrade(&ui.inner);
            let handle_events = move |evt, _evt_data, handle| {
                if let Some(ui) = evt_ui.upgrade() {
                    match evt {
                        E::OnButtonClick => 
                            if &handle == &ui.hello_button {
                                BasicApp::say_hello(&ui);
                            },
                        E::OnWindowClose => 
                            if &handle == &ui.window {
                                BasicApp::say_goodbye(&ui);
                            },
                        _ => {}
                    }
                }
            };

           *ui.default_handler.borrow_mut() = Some(nwg::full_bind_event_handler(&ui.window.handle, handle_events));

           // Layouts
           nwg::GridLayout::builder()
            .parent(&ui.window)
            .spacing(1)
            .child(0, 0, &ui.name_edit)
            .child_item(nwg::GridLayoutItem::new(&ui.hello_button, 0, 1, 1, 2))
            .build(&ui.layout)?;

            return Ok(ui);
        }
    }

    impl Drop for BasicAppUi {
        /// To make sure that everything is freed without issues, the default handler must be unbound.
        fn drop(&mut self) {
            let handler = self.default_handler.borrow();
            if handler.is_some() {
                nwg::unbind_event_handler(handler.as_ref().unwrap());
            }
        }
    }

    impl Deref for BasicAppUi {
        type Target = BasicApp;

        fn deref(&self) -> &BasicApp {
            &self.inner
        }
    }
}

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");
    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");
    let _ui = BasicApp::build_ui(Default::default()).expect("Failed to build UI");
    nwg::dispatch_thread_events();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rust: Native Windows GUI下载、安装、演示入门 的相关文章

随机推荐

  • SpringMVC-02 MVC模式介绍

    文章目录 1 Java Web开发模型2 JSP 43 JavaBean开发模型 xff08 model1 xff09 3 MVC开发模式 xff08 model2 xff09 3 1 MVC模式基础3 1 1 模型 视图 控制器各部分的作
  • 系统架构师-科目1考点

  • 系统架构师-科目2考点

  • 系统架构师-科目3考点

  • Hive笔记-01 架构概述

    文章目录 1 概述2 Metadata Metastore的作用3 Metastore三种配置方式3 1 Hive配置参数说明3 1 1 基本配置参数3 1 2 其他配置参数 3 2 内嵌模式 xff08 Embedded xff09 3
  • Hadoop笔记-01概述

    文章目录 1 什么是大数据 xff1f 1 1 大数据计算模式及代表产品1 2 云计算与物联网1 2 1 云计算1 2 1 1 虚拟化1 2 1 2 分布式存储1 2 1 3 分布式计算1 2 1 4 多租户 1 3 物联网1 3 1 识别
  • Hadoop笔记-02 安装

    文章目录 1 VBOX安装CentOS71 1 安装VBOX软件1 2 下载CentOS7镜像文件1 3 初始化VBOX虚拟盘1 4 CentOS7网络配置1 5 CentOS7 yum源配置1 6 CentOS7 一般配置1 6 1关闭防
  • ffmpeg播放器实现详解 - 视频同步控制

    1 时间戳 时间戳的概念贯穿音视频开发始终 xff0c 重要性不言而喻 时间戳告诉我们在什么时候 xff0c 用多快的速度去播哪一帧 xff0c 其中 xff0c DTS decoding timestamp 告诉我们何时解码 xff0c
  • Ubuntu22.04 安装深度微信报错 依赖: libsasl2-2 (>= 2.1.27.1)

    现象 xff1a span class token punctuation span base span class token punctuation span pang 64 pang HP span class token funct
  • Ubuntu22.04更新后 点击深度微信无反应

    系统版本 xff1a Ubuntu 22 04 jammy内核 xff1a x86 64 Linux 5 15 0 53 genericdeepin wine6 stable 版本 xff1a 6 0 0 41 1 深度微信图标点击后 xf
  • MySQL笔记-08 索引

    文章目录 1 索引概述1 1 MySQL索引分类1 1 1 普通索引1 1 2 唯一性索引1 1 3 全文索引1 1 4 单列索引1 1 5 多列索引1 1 6 空间索引 2 创建索引2 1 在建立数据表时创建索引2 1 1 普通索引创建2
  • MySQL笔记-09 视图

    文章目录 1 视图概念1 1 概念1 2 作用 2 创建视图2 1 查看创建视图的权限2 2 创建视图的步骤2 3 创建视图的注意事项 3 视图操作3 1 查看视图3 1 1 DESCRIBE语句3 1 2 SHOW TABLE STATU
  • MySQL笔记-10 数据完整性约束

    文章目录 1 定义完整性约束1 1 实体完整性1 1 1 主键约束1 1 2 候选键约束 1 2 参照完整性1 3 用户定义完整性1 3 1 非空约束1 3 2 CHECK约束1 3 2 1 对列实施CHECK约束1 3 2 2 对表实施C
  • Linux命令行笔记-00 综述

    文章目录 1 Linux命令行简介1 1 Linux命令行的分类1 1 1 根据系统中作用来分类1 1 2 根据对象来分类 2 Linux命令行解释器2 1 命令行解释器shell2 1 1 核心程序2 1 2 公用程序shell2 1 3
  • Linux命令行笔记-01 文件管理-文件的建立、移动和删除

    文章目录 1 文件的建立 移动和删除1 1 96 cat 96 建立文件1 1 1 语法格式与参数1 1 2 示例 1 2 96 touch 96 建立文件1 2 1 语法格式与参数1 2 2 示例1 2 3 注意 1 3 96 ln 96
  • CMake学习-01 综述

    文章目录 1 CMake1 1 CMake生成makefile并编译的流程 2 CMakeLists txt2 1 Demo讲解2 2 常用命令2 2 1 指定CMAKE的最低版本2 2 2 设置项目名称2 2 3 设置变量2 2 4 设置
  • Rust:官方迭代器大全

    一 for 和迭代器 先看一段代码 xff1a span class token keyword fn span span class token function definition function main span span cl
  • Rust: 函数的重载——我做的的一组小实验

    编程的时候 xff0c 我发现有不少函数能够根据左值类型自动调用重载函数 但是 xff0c 我知道 Rust 的函数是不支持重载的 所以我打算尝试一下这一 重载 现象是如何实现的 一 Rust 不支持函数重载 写一段代码 xff1a spa
  • php产生大量session文件导致报错无法创建修改文件:no space left on device

    阿里云SLB健康检测后端服务器组产生百万级别的php的0k大小session文件 今天早上在登录公司一台阿里云的服务器上vim修改配置文件以及touch文件时报错 xff1a no space left on device df h 查看了
  • Rust: Native Windows GUI下载、安装、演示入门

    上 github 下载 xff0c 网址为 https github com gabdube native windows gui 上面有安装说明 按说明方法 xff0c 老是提示权限不够 配置了 ssh 公钥证书 xff0c 仍然不行 请