rust gtk 桌面应用 demo

news2024/11/23 19:18:19

《精通Rust》里介绍了 GTK+框架的开发,这篇博客记录并扩展一下。rust 可以用于桌面应用开发,我还挺惊讶的,大学的时候也有学习过 VC++,对桌面编程一直都很感兴趣,而且一直有一种妄念,总觉得自己能开发一款很好用的桌面程序,就和总觉得自己能彩票中大奖一样。

环境安装

可能你会需要安装 gtk+3。如果执行 cargo build 的时候提示你找不到 gdk-3.0,那你就需要手动安装一下:
在这里插入图片描述

不过,也不需要提前安装这些依赖。当我们执行 cargo build 编译的时候,结合 rust 的错误提示进行按需安装是比较稳妥的。

功能开发

在《精通Rust》书中的16章节,书中的 Demo 忽略了一个非常重要的细节,就是省略了依赖包的声明,没有依赖包的声明,代码就缺少了灵魂,编译都没有办法通过。

我在考虑要不要使用 GPT 自动生成一下源码,省的麻烦。自动生成代码还是放到最后吧…可以通过这个过程来熟悉一下 rust 的函数。

std::process::exit

这个函数并不陌生,使用一个 code 来退出当前的进程。要想在程序中正常调用这个函数,需要导入如下的头声明:

use std::process;

gtk::Window

代码中使用到的组件都来自于 gtk 包,为了方便起见,可以将 gtk 下的声明全局导入

use gtk::*

std::sync::mpsc::Sender

用来通过 channel 实现异步通讯的能力,代码中用来做数据通讯,有 send 和对应的 try_recv 的两个动作。如果我们不引入这个包,cargo build 还会给我们另一个可选建议 glib::Sender,不过这个函数的解释中提到,两个方式是类似的。

use std::sync::mpsc::Sender

std::sync::mpsc::Receiver

有消息的发送,就应该有消息的接受

use std::sync::mpsc::Receiver

std::sync::mpsc::channel

函数用来创建 Sender、Receive,和上面两个函数是一体的,它创建的是一个异步队列。创建同步队列需要调用 std::sync::mpsc::sync_channel方法。

use std::sync::mpsc::channel

mod

rust 在相同的目录下,不同文件中声明的结构体是无法相互引用的,需要通过 mod 来解决。mod 主要用来解决项目内代码组织的问题,use mod xxx 会尝试去加载当前目录下的 xxx.rs 文件的代码。

在 main.rs 中的 mod hackernews 就是用来加载 hackernews.rs 中声明的导出方法或结构体。如果你将这行代码删除,程序就会找不到文件中声明的 Story 结构体。

use crate::hackernews::Story;

std::sync::Arc

全称是 Atomically Reference Counted,表示线程安全的引用计数器。Arc 表示一个指针,指向堆空间的 T 值。同时,有一个附属的引用计数。

use std::sync::Arc;

reqwest::Client

一个异步的 HTTP 请求客户端,用来发送 HTTP 请求。在说明文档中明确强调:我们不需要使用 Rc 或者 Arc 去包装这个类型,内部已经使用 Arc 包装过了。

use reqwest::Client;

glib::source::timeout_add

函数用于固定间隔执行闭包函数,示例中的作用是固定间隔尝试接受消息。我发现,rust 依赖包的做法特别接近 javascript 。

函数第一个参数的类型是 core::time::Duration,这个时间概念和 Go 语言相近,不过 rust 表示的是秒+毫秒的单位,构造时间的时候可以传递秒和毫秒两个数值。

use glib::source::timeout_add;

std::ops::ControlFlow

代码示例中 ControlFlow::Continue(true),目前来看这个 Continue 的含义并不明确,感觉不到它的价值。

use std::ops::ControlFlow
impl App {
    pub fn new() -> (App, Receiver<Msg>) {
        if gtk::init().is_err() {
            println!("Failed to init hews window");
            process::exit(1);
        }

        let (tx, rx) = channel();
        let window = gtk::Window::new(gtk::WindowType::Toplevel);
        let sw = ScrolledWindow::new(None, None);
        let stories = gtk::Box::new(gtk::Orientation::Vertical, 20);
        let spinner = gtk::Spinner::new();
        let header = Header::new(stories.clone(), tx.clone());

        stories.pack_start(&spinner, false, false, 2);
        sw.add(&stories);
        window.add(&sw);
        window.set_default_size(600, 350);
        window.set_titlebar(&header.header);

        window.connect_delete_event(move |_, _| {
            main_quit();
            Inhibit(false);
        });
    }

    pub fn launch(&self, rx: Receiver<Msg>) {
        self.window.show_all();
        let client = Arc::new(reqwest::Client::new());
        self.fetch_posts(client.clone());
        self.run_event_loop(rx, client);
    }

    fn fetch_posts(&self, client: Arc<Client>) {
        self.spinner.start();
        self.tx.send(Msg::Loading).unwrap();
        let tx_clone = self.tx.clone();
        top_stories(client, 10, &tx_clone);
    }

    fn run_event_loop(&self, rx: Receiver<Msg>, client: Arc<Client>) {
        let container = self.stories.clone();
        let spinner = self.spinner.clone();
        let header = self.header.clone();
        let tx_clone = self.tx.clone();

        timeout_add(100, move || {
            match rx.try_recv() {
                Ok(Msg::NewStory(s)) => App::render_story(s, &container),
                Ok(Msg::Loading) => header.disable_refresh(),
                Ok(Msg::Loaded) => {
                    spinner.stop();
                    header.enable_refresh();
                }
                Ok(Msg::Refresh) => {
                    spinner.start();
                    spinner.show();
                    (&tx_clone).send(Msg::Loading).unwrap();
                    top_stories(client.clone(), 10, &tx_clone)
                }
                Err(_) => {}
            }
            Continue(true)
        });

        gtk::main();
    }

    fn render_story(s: Stroy, stories: &gtk::Box) {
        let title_with_score = format!("{} ({})", s.title, s.score);
        let label = gtk::Label::new(&*title_with_score);
        let story_url = s.url.unwrap_or("N/A".to_string());
        let link_label = gtk::Label::new(&*story_url);
        let label_markup = format!("<a href=\"{}\">{}</a>", story_url, story_url);

        link_label.set_markup(&label_markup);
        stories.pack_start(&label, false, false, 2);
        stories.pack_start(&link_label, false, false, 2);
        stories.show_all();
    }
}

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

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

相关文章

Rust之通用编程

1、变量与可变性&#xff1a; 在Rust语言中&#xff0c;变量默认是不可变的&#xff0c;所以一旦变量被绑定到某个值上面&#xff0c;这个值就再也无法被改变。 可以通过在声明的变量名称前添加mut关键字来使其可变。除了使变量的值可变&#xff0c;mut还会向阅读代码的人暗示…

“C++基础入门指南:了解语言特性和基本语法”

C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式 等。熟悉C语言之后&#xff0c;对C学习有一定的帮助 文章目录 C命名风格C关键字(C98)C命名空间命名空间定义命名空间使用命名空间的使用有三种方式&#xff…

Android - 集成三方模组原厂WiFi Hal库问题

Android - 集成三方模组原厂WiFi Hal库问题 最近Android 11产品平台上需要集成三方WiFi/AP模组厂商提供的hal静态库时遇到一个问题&#xff1a;将三方的库代码集成进系统&#xff0c;并正确配置、编译出lib_driver_cmd_xxx.a(xxx一般是厂商的名字缩写&#xff0c;仅仅是个后缀用…

gazebo simulation

<?xml version"1.0" ?> <!-- --> <!-- | This document was autogenerated by xacro from /home/xrh/ros-project/gazebo_test/src/fmauch_universal_robot/ur_description/urdf/ur3_D455_2f140.urdf.xacro | --> <!-- | EDITING THIS…

C++---string

String C语言中的字符串和C中的string类标准库中的string类string类的常用接口string类对象的常见构造string类对象的容量操作string类对象的访问及遍历操作 C语言中的字符串和C中的string类 在C语言中&#xff0c;字符串是一个字符数组&#xff0c;它以空字符\0结尾&#xff…

【进程7】 2.15 有名管道介绍及使用 2.16有名管道实现简单版聊天功能

2.15 有名管道介绍及使用 有名管道&#xff08;FIFO first in first out&#xff09; 有名管道也可用于具有亲缘关系的进程之间&#xff0c;底层数据结构也是环形队列、循环队列。 有名管道的使用 unlink用于删除一个文件。 创建fifo文件 命令&#xff1a; 文件类型p&…

Android-WebRTC-双人视频

省略开启本机摄像头的过程 以下和WebSocket通信的时候&#xff0c;是通过Gson转对象为字符串的方式传输的数据 整个过程 layout_rtc.xml <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:and…

汽车ECU刷机笔记

汽车ECU刷机笔记 ECU简介ECU刷机的意义点火提前角点火延迟角调整意义 常见刷ECU的方法:成本价格1.通过obd汽车诊断口读写数据2.bdm后台调试模式3.BENCH刷写4.BOOT需要拆开电脑板&#xff0c;焊接电路 ECU刷写程序读取数据OBD tools(汽车诊断器)蓝牙ODB诊断器&#xff1a; 读写设…

<j-editable-table 隐藏一列表格数据

&#xff1c;j-editable-table 隐藏一列表格数据 隐藏条码 本来列代码是这样的 {title: 条码, key: barCode, width: 15%, type: FormTypes.input, defaultValue: , placeholder: 请输入${title},validateRules: [{ required: true, message: ${title}不能为空 },// { pattern…

二分搜索树的特性

一、顺序性 二分搜索树可以当做查找表的一种实现。 我们使用二分搜索树的目的是通过查找 key 马上得到 value。minimum、maximum、successor&#xff08;后继&#xff09;、predecessor&#xff08;前驱&#xff09;、floor&#xff08;地板&#xff09;、ceil&#xff08;天…

leetcode 699. 掉落的方块(java)

掉落的方块 leetcode 699. 掉落的方块题目描述线段树解法代码演示 leetcode 699. 掉落的方块 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/falling-squares 题目描述 在二维平面上的 x 轴上&#xff0c;放置着一些方块…

jmeter软件测试实验(附源码以及配置)

jmeter介绍 JMeter是一个开源的性能测试工具&#xff0c;由Apache软件基金会开发和维护。它主要用于对Web应用程序、Web服务、数据库和其他类型的服务进行性能测试。JMeter最初是为测试Web应用程序而设计的&#xff0c;但现在已经扩展到支持更广泛的应用场景。 JMeter 可对服务…

Linux系统入门之-系统编程【open、close函数】

继上一篇环境配置后就正式开始系统编程 RK3568开发板入门之-tftp&nfs的配置 open的使用&#xff0c;使用之前可以先在Ubuntu下查看帮助&#xff0c;了解open的使用和语法&#xff0c;如下&#xff1a; man 2 open对于open函数 *pathname&#xff1a;要打开的文件路径 f…

【JavaWeb】Tomcat底层机制和Servlet运行原理

&#x1f384;欢迎来到dandelionl_的csdn博文&#xff0c;本文主要讲解Java web中Tomcat底层机制和Servlet的运行原理的相关知识&#x1f384; &#x1f308;我是dandelionl_&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一…

Revisiting Personalized Federated Learning:Robustness Against Backdoor Attacks

ACM SIGKDD Conference on Knowledge Discovery and Data Mining 2023 秦泽钰&#xff0c;香港科技大学计算机科学与工程系博士生&#xff0c;联邦学习中个性化的额外增益&#xff1a;对于后门攻击的鲁棒性 https://github.com/alibaba/FederatedScope/tree/backdoor-bench 摘要…

MySQL两种安装方式

数据库&#xff1a; 一、 二、 三、 四、 五、MySQL的两种安装方式 .zip包的安装方式&#xff1a; .msi方式安装的需要到控制面板卸载 密码默认是空密码 5.7和8.0开始&#xff1a;加强安全相关操作&#xff0c;安装有所不同 前三步一样&#xff0c;第四步在cmd&#xff0c;以…

windows系统安装异构虚拟机arm版的银河麒麟服务器

下载qemu UEFI&#xff08;BIOS的替代方案&#xff09;的下载地址&#xff1a;http://releases.linaro.org/components/kernel/uefi-linaro/16.02/release/qemu64/QEMU_EFI.fd QEMU 软件的下载地址&#xff1a;https://qemu.weilnetz.de/w64/2021/qemu-w64-setup-20210505.exe …

Docker详解及常用命令介绍

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

【5】构建手写数字模型

1 mnist数据集 下载数据集&#xff1a; 手动下载&#xff1a;MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges tf程序下载&#xff1a; tensorflow2.x将数据集集成在Keras中。tensorflow2.0&#xff0c;更新删除了input_data的函数。 import…

19.主题时钟

主题时钟 html部分 <div class"btn">黑色</div><div class"clock-container"><div class"time">21</div><div class"date">21</div><div class"clock"><div class&qu…