30天拿下Rust之图形编程

这篇具有很好参考价值的文章主要介绍了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 图形库,30天拿下Rust,rust,开发语言,后端,图形编程,GTK-rs,Iced

总结

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

到了这里,关于30天拿下Rust之图形编程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 30天拿下Rust之HashMap

    概述         HashMap,被称为哈希表或散列表,是一种可以存储键值对的数据结构。它使用哈希函数将键映射到存储位置,以便可以快速检索和更新元素。这种数据结构在许多编程语言中都存在,而在Rust中,它被实现为HashMapK, V。其中,K表示键的类型,V表示值的类型。H

    2024年03月17日
    浏览(43)
  • 30天拿下Rust之生命周期

    概述         在Rust中,生命周期是一个非常重要的概念,是保证内存安全和防止悬垂引用的核心机制之一。通过精确地跟踪引用的生命周期,Rust能够在编译阶段就防止许多其他语言在运行时才会遇到的内存问题。在Rust中,生命周期代表了引用的有效时间段。当我们创建

    2024年03月20日
    浏览(45)
  • 30天拿下Rust之面向对象

    概述         在编程语言的世界中,Rust以其独特的内存安全、并发控制和高性能特性吸引了众多开发者。虽然Rust并非传统的面向对象编程语言(比如:C++、Java),但它依然支持并提供了一种颇具特色的面向对象编程方式,以实现类似于面向对象的编程范式。        

    2024年04月15日
    浏览(40)
  • 30天拿下Rust之错误处理

    概述         在软件开发领域,对错误的妥善处理是保证程序稳定性和健壮性的重要环节。Rust作为一种系统级编程语言,以其对内存安全和所有权的独特设计而著称,其错误处理机制同样体现了Rust的严谨与实用。在Rust中,错误处理通常分为两大类:不可恢复的错误和可

    2024年03月21日
    浏览(66)
  • 30天拿下Rust之Trait

    概述         在Rust中,Trait是一个核心概念,它允许我们定义类型应该具有的行为。Trait类似于其他语言中的接口,但Rust的Trait更为强大和灵活。它不仅定义了一组方法,还允许我们指定方法的默认实现、泛型约束和继承。通过Trait,我们可以定义一组方法的签名和关联类

    2024年03月17日
    浏览(35)
  • 30天拿下Rust之输入输出

    概述         在软件开发中,输入输出(I/O)是任何应用程序的基本构建模块。Rust作为一门注重安全和性能的语言,在其标准库中提供了强大的I/O功能。这些功能使得Rust程序员能够非常轻松地进行标准I/O、文件读写等操作。 标准I/O         在Rust中,标准输入通常通

    2024年03月24日
    浏览(39)
  • 30天拿下Rust之高级类型

    概述         Rust作为一门系统编程语言,以其独特的内存管理方式和强大的类型系统著称。其中,高级类型的应用,为Rust的开发者提供了丰富的编程工具和手段,使得开发者可以更加灵活和高效地进行编程。 Newtype模式         Newtype模式是一种轻量级的设计模式,用

    2024年04月15日
    浏览(45)
  • 30天拿下Rust之命令行参数

    概述         在Rust中,命令行参数是程序从命令行接收的输入,它们为程序提供了运行时配置和数据的灵活性。对于需要用户交互或自动化脚本的Rust程序来说,正确地解析命令行参数至关重要。通过std::env::args和第三方库(比如:clap),我们可以轻松地获取和解析命令行

    2024年03月26日
    浏览(40)
  • 30天拿下Rust之字符串

    概述         在Rust中,字符串是一种非常重要的数据类型,用于处理文本数据。Rust的字符串是以UTF-8编码的字节序列,主要有两种类型:str和String。其中,str是一个对字符数据的不可变引用,更像是对现有字符串数据的“视图”,而String则是一个独立、可变更的字符串实

    2024年03月12日
    浏览(46)
  • 30天拿下Rust之所有权

    概述         在编程语言的世界中,Rust凭借其独特的所有权机制脱颖而出,为开发者提供了一种新颖而强大的工具来防止内存错误。这一特性不仅确保了代码的安全性,还极大地提升了程序的性能。在Rust中,所有权是一种编译时检查机制,用于追踪哪些内存或资源何时可

    2024年03月08日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包