30天拿下Rust之图形编程

概述

        Rust语言以其卓越的安全性、性能和可靠性赢得了广大开发者的青睐,逐渐在系统编程、网络服务、游戏开发等领域崭露头角。随着Rust生态的日益繁荣,图形编程领域也涌现出一批优秀的框架和库,使得用Rust进行高效、安全的图形应用开发成为可能。

图形库对比

        在Rust中,有多个图形库可供选择,其中一些最流行的包括:GTK-rs、Iced、Egui等。这些库提供了与GPU进行交互的接口,封装了底层的图形API,使得开发者能够更轻松地构建图形应用。下面,我们将分别介绍这些图形库。

        GTK-rs:作为GTK的Rust绑定,GTK-rs借助GTK本身的广泛使用和成熟度,提供了跨平台的GUI开发能力。GTK本身在Linux社区尤其流行,因此对于需要在Linux上开发桌面应用的Rust开发者而言,GTK-rs是一个自然的选择。其活跃的社区、良好的文档和稳定的更新,使其保持较高的流行度。

        Iced:Iced以其简洁的API设计、现代的外观和对跨平台的支持受到欢迎。它强调快速、可靠和易于定制,适合开发轻量级到中等复杂度的桌面应用。Iced有着活跃的开发进度、详尽的文档和教程,以及相对较大的用户群体,使其在Rust GUI库中占据显著位置。

        Druid:Druid提供了一个完整的桌面应用程序框架,结合了Egui图形库,强调高性能和自定义能力。虽然可能不如GTK-rs或Iced那么广为人知,但其新颖的设计理念和特定领域的优秀表现吸引了部分开发者关注。

        Egui:Egui是一个即时模式GUI库,以其小巧、易用和跨平台特性受到关注,特别适用于嵌入到游戏和其他应用程序中。Egui的更新频繁,社区活跃度较高,且由于其轻量化和灵活性,可能在某些特定场景下被开发者广泛采用。

        Fltk-rs:Fltk-rs作为FLTK C++ GUI库的Rust绑定,以其小巧的尺寸、高效的性能和易用性著称,特别适合开发轻量级工具软件。其简单快速的开发流程和较小的运行时资源占用,可能会吸引一部分追求简洁和高效的开发者。

GTK-rs库的使用

        GTK-rs是Rust的一个GTK绑定,它使得Rust开发者能够使用GTK库来创建跨平台的图形用户界面。GTK库本身是一个非常流行且功能强大的GUI库,提供了丰富的控件和布局方式。通过使用GTK-rs,Rust开发者可以享受到GTK的便利和强大功能,同时保留Rust语言的类型安全和内存安全特性。

        要使用GTK-rs库,首先,需要在Rust项目中添加GTK-rs的依赖。打开Cargo.toml文件,并添加如下内容。

[dependencies]
gtk = "0.15"

        其次,需要先初始化GTK环境,这通常是在main函数的开始处使用gtk::init()方法完成的。

        接下来,我们可以通过gtk::ApplicationWindow::new()方法创建一个窗口,并设置其标题和默认尺寸。

        GTK-rs库提供了丰富的控件供我们选择,比如:按钮、文本框等。在下面的示例代码中,我们首先创建了一个带有标签的按钮,连接了一个点击事件处理器。当按钮被点击时,它会打印一条消息到控制台。然后,我们将按钮添加到了窗口的内容区域。接下来,我们连接了一个删除事件处理器到窗口。当用户关闭窗口时,这个处理器会被调用,并调用gtk::main_quit来退出事件循环。最后,我们调用gtk::main来启动事件循环。

extern crate gtk;use gtk::prelude::*;fn main() {if gtk::init().is_err() {println!("Unable to initialize GTK.");return;} let window = gtk::ApplicationWindow::new(None::<&gtk::Application>);window.set_title("Demo");window.set_default_size(600, 500);let btn = gtk::Button::new_with_label("Click me");btn.connect_clicked(move |_| {println!("Button clicked");});let content = window.get_content_area();content.add(&btn);window.connect_delete_event(|_, _| {gtk::main_quit();Inhibit(true)});window.show_all();gtk::main();
}

Iced库的使用

        Iced是一个用于构建跨平台、高性能用户界面的Rust图形库。它采用了Elm架构和反应式编程模型,使得编写声明式、易于推理的UI代码成为可能。Iced提供了一套丰富的widget库,可用于构建复杂的界面,并且支持原生的窗口系统集成,确保应用程序在Windows、macOS、Linux等平台上具有良好的用户体验。

        在Iced库中,引入了一些图像编程相关的基本概念,主要包括:Widgets、Views、Events & Messages、Application Loop。

        Widgets

        Iced中的UI是由一系列可重用的组件(称为widgets)构建起来的。这些组件包括:按钮、文本、输入框、滑块、列表、表格等各种常见UI元素。每个widget都有自己的状态和样式属性,可以响应用户交互并触发事件。

        Views

        在Iced中,View是一个函数,它定义了如何根据应用程序的状态生成特定的UI结构。当状态改变时,View函数会被重新调用,生成新的widget树,这种机制确保了UI总是反映最新的应用程序状态。

        Events & Messages

        用户与UI的交互会产生events,这些事件被传递给应用程序,通常触发状态更新。状态更新通过发送messages来完成,消息是应用程序内部定义的数据结构,用于描述状态变化请求。消息通过update函数处理,并最终导致状态变更和视图重新渲染。

        Application Loop

        Iced应用程序遵循一个典型的工作循环,主要包括以下三个步骤。

        1、Update: 处理传入的消息,更新应用程序状态。

        2、Layout: 根据新的状态计算widget树的布局信息。

        3、Paint: 使用布局信息和样式渲染widget到屏幕。

        要使用Iced库,需要在Rust项目中添加Iced的依赖。打开Cargo.toml文件,并添加如下内容。

[dependencies]
iced = { version = "0.12", features = ["canvas", "tokio", "debug"] }
time = { version = "0.3", features = ["local-offset"] }

        在下面的示例代码中,我们实现了一个图形化的模拟时钟应用程序。该应用具备以下三个核心特性。

        1、实时更新:应用程序每隔500毫秒通过订阅系统触发一次Message::Tick消息,更新当前显示的时间。

        2、自定义外观:在画布(canvas)上绘制模拟时钟,包括:背景色、指针(时针、分针、秒针)及指针宽度。指针长度和旋转角度,与实际时间同步。

        3、响应式布局:时钟容器采用响应式设计,填充其父容器的可用空间,并带有内边距。


use iced::executor;
use iced::mouse;
use iced::widget::canvas::{stroke, Cache, Geometry, LineCap, Path, Stroke};
use iced::widget::{canvas, container};
use iced::{Application, Color, Command, Element, Length, Point, Rectangle, Renderer,Settings, Subscription, Theme, Vector,
};pub fn main() -> iced::Result {Clock::run(Settings {antialiasing: true,..Settings::default()})
}struct Clock {now: time::OffsetDateTime,clock: Cache,
}#[derive(Debug, Clone, Copy)]
enum Message {Tick(time::OffsetDateTime),
}impl Application for Clock {type Executor = executor::Default;type Message = Message;type Theme = Theme;type Flags = ();fn new(_flags: ()) -> (Self, Command<Message>) {(Clock {now: time::OffsetDateTime::now_local().unwrap_or_else(|_| time::OffsetDateTime::now_utc()),clock: Cache::default(),},Command::none(),)}fn title(&self) -> String {String::from("Clock")}fn update(&mut self, message: Message) -> Command<Message> {match message {Message::Tick(local_time) => {let now = local_time;if now != self.now {self.now = now;self.clock.clear();}}}Command::none()}fn view(&self) -> Element<Message> {let canvas = canvas(self as &Self).width(Length::Fill).height(Length::Fill);container(canvas).width(Length::Fill).height(Length::Fill).padding(20).into()}fn subscription(&self) -> Subscription<Message> {iced::time::every(std::time::Duration::from_millis(500)).map(|_| {Message::Tick(time::OffsetDateTime::now_local().unwrap_or_else(|_| time::OffsetDateTime::now_utc()),)})}
}impl<Message> canvas::Program<Message> for Clock {type State = ();fn draw(&self,_state: &Self::State,renderer: &Renderer,_theme: &Theme,bounds: Rectangle,_cursor: mouse::Cursor,) -> Vec<Geometry> {let clock = self.clock.draw(renderer, bounds.size(), |frame| {let center = frame.center();let radius = frame.width().min(frame.height()) / 2.0;let background = Path::circle(center, radius);frame.fill(&background, Color::from_rgb8(0x12, 0x93, 0xD8));let short_hand =Path::line(Point::ORIGIN, Point::new(0.0, -0.5 * radius));let long_hand =Path::line(Point::ORIGIN, Point::new(0.0, -0.8 * radius));let width = radius / 100.0;let thin_stroke = || -> Stroke {Stroke {width,style: stroke::Style::Solid(Color::WHITE),line_cap: LineCap::Round,..Stroke::default()}};let wide_stroke = || -> Stroke {Stroke {width: width * 3.0,style: stroke::Style::Solid(Color::WHITE),line_cap: LineCap::Round,..Stroke::default()}};frame.translate(Vector::new(center.x, center.y));frame.with_save(|frame| {frame.rotate(hand_rotation(self.now.hour(), 12));frame.stroke(&short_hand, wide_stroke());});frame.with_save(|frame| {frame.rotate(hand_rotation(self.now.minute(), 60));frame.stroke(&long_hand, wide_stroke());});frame.with_save(|frame| {frame.rotate(hand_rotation(self.now.second(), 60));frame.stroke(&long_hand, thin_stroke());});});vec![clock]}
}fn hand_rotation(n: u8, total: u8) -> f32 {let turns = n as f32 / total as f32;2.0 * std::f32::consts::PI * turns
}

        执行该程序后,其运行效果大致如下。

总结

        Rust凭借其安全、高性能的特点,以及逐渐成熟的图形库和生态系统,已成为图形编程领域的一股重要力量,适用于从轻量级GUI应用到高性能游戏引擎的各种图形开发场景。随着社区的发展和新技术的融合,Rust在图形编程领域的影响力有望进一步增强。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/5337.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT学习之QtXlsx

背景&#xff1a; 本来我是想提取xml中的信息存在xlsx文件中的&#xff0c;网上很多说是使用QtXlsx&#xff1b; 于是我找了一些帖&#xff0c; 像&#xff1a;https://www.cnblogs.com/liming19680104/p/14398459.html&#xff1b; 大家的说法都是安装第三方库到QT中&#xff…

「AIGC」如何理解大语言模型

一、Transformer模型 Transformer模型是一种基于自注意力机制的架构&#xff0c;由Vaswani等人在2017年的论文《Attention Is All You Need》中首次提出。它主要用于处理序列到序列的任务&#xff0c;如机器翻译、文本摘要等。 案例&#xff1a;机器翻译 假设我们想将英文句子…

OLTP和OLAP,StarRocks数据库,TiDB数据库

OLTP和OLAP&#xff0c;StarRocks数据库&#xff0c;TiDB数据库 一、OLTP和OLAP二、StarRocks数据库三、TiDB数据库 一、OLTP和OLAP OLTP和OLAP是两种不同的数据处理方式&#xff0c;用于处理不同类型的工作负载。OLTP&#xff08;Online Transaction Processing&#xff09;是…

leetcode18-4Sum

题目 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#xff09;&#xff1a; 0 &l…

ECharts在网页中添加可视化图标-在网页中添加交互图表+option模块案列详解

一、引言 ECharts 是一个使用 JavaScript 编写的开源可视化库&#xff0c;它可以在浏览器中生成交互式的图表。无论是折线图、柱状图、散点图还是饼图&#xff0c;ECharts 都能轻松应对。本文将带领大家了解如何在网页中添加 ECharts 可视化图标。 本章可以直接跳到第五点完整…

XML 映射文件(Mapper 文件)的命名空间

MyBatis 中&#xff0c;mapper 命名空间是指一个 XML 映射文件&#xff08;Mapper 文件&#xff09;的命名空间。每个 Mapper 文件都有一个命名空间&#xff0c;用于定义与特定数据库表相关联的 SQL 映射规则和操作方法。 mapper 命名空间的作用包括&#xff1a; 命名空间的唯…

EOCR-SS-05W电子式过电流继电器 0.5-6A 施耐德韩国三和

三和EOCR株式会社是韩国的电动机保护器生产企业&#xff0c;公司由金仁锡博士&#xff08;施耐德电气集团韩国执行官&#xff09;于1981年建立。 2001年&#xff0c;为了把企业发展成性的、战略性企业&#xff0c;随后加入了法国施耐德电气集团公司。 EOCR主要产品有电子式电…

LeetCode 刷题 -- Day 6

今日题目 题目难度备注102. 二叉树的层序遍历 中等一招鲜吃遍天107. 二叉树的层序遍历 II &#xff09;中等199. 二叉树的右视图 中等637. 二叉树的层平均值简单429. N 叉树的层序遍历中等515. 在每个树行中找最大值中等116. 填充每个节点的下一个右侧节点指针中等104. 二叉树…

JAVA相关面试题分享

Java 基础知识 1.1 面向对象的特征&#xff08;了解&#xff09; 面向对象的特征&#xff1a;封装、继承、多态、抽象。 封装&#xff1a;就是把对象的属性和行为&#xff08;数据&#xff09;结合为一个独立的整体&#xff0c;并尽可能隐藏对 象的内部实现细节&#xff0c;就…

spring boot 定义启动页 到 login

当前办法只是针对 项目启动后 直接跳转到 指定静态页面 如果有验证身份 安全等问题 可以另外想办法 去添加 &#xff0c;需要的直接 拉过去使用 修改 【"redirect: 需要启动后访问到文件位置得地址 ”】 直接上代码 &#xff1a; import org.springframework.context…

Android手势识别面试问题及回答

问题 1: 如何在Android中实现基本的手势识别&#xff1f; 答案: 在Android中&#xff0c;可以通过使用GestureDetector类来实现基本的手势识别。首先需要创建一个GestureDetector的实例&#xff0c;并实现GestureDetector.OnGestureListener接口来响应各种手势事件&#xff0c…

LeeCode 1728 任意图上博弈

题意 传送门 LeeCode 1728 猫和老鼠 II 题解 任意图上博弈&#xff0c;可参考 Games on arbitrary graphs。具体而言&#xff0c;将博弈双方位置加之先后手状态看作任意图上的一个节点&#xff0c;并根据状态转移建立反图。对于可以确定胜负态的节点&#xff0c;以其为起点&…

【百度Apollo】探索自动驾驶:Apollo 新版本 Beta 全新的Dreamview+,便捷灵活更丰富

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引入一、Dreamview介绍二、Dreamview 新特性2.1、基于模式的多场景——流程更简洁地图视角调节&#xff1a;调试流…

自动驾驶系统中的端到端学习

资料下载-《自动驾驶系统中的端到端学习&#xff08;2020&#xff09;》https://mp.weixin.qq.com/s/ttNpsn7qyVWvDMZzluU_pA 近年来&#xff0c;卷积神经网络显著提高了视觉感知能力。实现这一成功的两个主要因素是将简单的模块组合成复杂的网络和端到端的优化。然而&#xf…

电影交流|基于SprinBoot+vue的电影交流平台小程序系统(源码+数据库+文档)

电影交流平台目录 目录 基于SprinBootvue的电影交流平台小程序系统 一、前言 二、系统设计 三、系统功能设计 1用户信息管理 2 电影信息管理 3公告信息管理 4论坛信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取…

设备能源数据采集新篇章

在当今这个信息化、智能化的时代&#xff0c;设备能源数据的采集已经成为企业高效运营、绿色发展的重要基石。而今天&#xff0c;我们要向大家介绍的就是一款颠覆传统、引领未来的设备能源数据采集神器——HiWoo Box网关&#xff01; 一、HiWoo Box网关&#xff1a;一站式解决…

二维码生成器,一站式解决方案,让您的数字生活更便捷

随着科技的飞速发展&#xff0c;二维码已经成为我们日常生活中不可或缺的一部分。无论是支付、身份验证还是信息传递&#xff0c;二维码都以其高效、便捷的特性赢得了广泛的应用。为了满足不同领域的需求&#xff0c;二维码生成器应运而生&#xff0c;为用户提供了一站式的解决…

解决clickhouse 启动报错

解决clickhouse 启动报错 Error response from daemon: driver failed programming external connectivity on endpoint clickhouse-server (b42457434cebe7d8ad024d31e4fd28eae2139bb2b5046c283bea17ce4398d5b0): Error starting userland proxy: listen tcp4 0.0.0.0:8123: …

RocketMQ MQTT 快速搭建验证

来自业务的需求&#xff0c;需要快速搭建一套支持 MQTT 协议的消息系统。 前期准备&#xff1a; 官方地址&#xff1a;https://github.com/apache/rocketmq-mqtt RocketMQ从4.9.3 版本开始才支持该功能&#xff0c;所以需要先检查 RocketMQ 的版本是否满足。 RocketMQ 部署参…

【知识分享】html+js实现系统拍照上传功能

htmljs实现系统拍照上传功能 <!DOCTYPE html> <html> <head><meta charset"UTF-8"><meta name"Keywords" content""/><meta name"Description" content""/><meta http-equiv"X…