rust gtk 桌面应用 demo
《精通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
gtk::Box | gtk::prelude::BoxExt
其中,gtk::prelude::BoxExt 属于 trait 属性,rust 中的 trait 等同于 go 语言的 interface 类型,也是实现多态的手段之一
trait 特性需要明确声明出来,否则,trait 特性会被掩藏。所以,下面的两个都需要导入:
use gtk::Box;
use gtk::prelude::BoxExt;
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: >k::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();}
}
相关文章:

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

《嵌入式 - 工具》J-link读写MCU内部Flash
1 J-Link简介 J-Link是SEGGER公司为支持仿真ARM内核芯片推出的JTAG仿真器。配合IAR EWAR,ADS,KEIL,WINARM,RealView等集成开发环境支持所有ARM7/ARM9/ARM11,Cortex M0/M1/M3/M4, Cortex A5/A8/A9等内核芯片的仿真,是学…...
算法练习-LeetCode1071. Greatest Common Divisor of Strings
题目地址:LeetCode - The Worlds Leading Online Programming Learning Platform Description: For two strings s and t, we say "t divides s" if and only if s t ... t (i.e., t is concatenated with itself one or more times). Given two strin…...
Nuget不小心用sudo下载后怎么在user里使用
问题发生 协同开发的过程中,同时在dotnet里面添加了nuget的grpc包,在不清楚的情况下执行自动生成脚本,下载nuget包失败,说是权限不足,于是就使用了sudo进行自动生成,结果在下一次重新打包的过程中ÿ…...
软件测试技能大赛环境搭建及系统部署报告
环境搭建及系统部署报告 环境搭建与配置过程(附图) JDK环境变量配置截图 【截取JDK环境变量配置截图】 查看JDK版本信息截图 【截取使用命令查看JDK版本信息截图,必须截取查看信息成功截图】 root账号成功登录MySQL截图 【截取使用root账…...

浅谈现代通信技术
目录 1.传统通信方法 2.传统通信方式的缺点 3.现代通信技术 4.现代通信技术给人类带来的福利 1.传统通信方法 传统通信方法指的是在数字化通信之前使用的传统的通信方式。以下是一些常见的传统通信方法: 1. 书信:通过邮件或快递等方式发送纸质信件。这…...

windows环境下adb 下载和配置,连接手机。
ADB下载地址: https://adbdownload.com/ 选择下载windows系统的。 下载后解压,查看adb.exe所在的目录,如下 这里将路径复制下来:D:\ADB 配置到系统环境变量中。 然后再打开cmd,输入adb version查看版本。 出现…...

[STL]list使用介绍
[STL]list使用 注:本文测试环境是visual studio2019。 文章目录 [STL]list使用1. list介绍2. 构造函数3. 迭代器相关函数begin函数和end函数rbegin函数和rend函数 4. 容量相关函数empty函数size函数 5. 数据修改函数push_back函数和pop_back函数push_front函数和pop…...
k8s服务发现之第五弹--使用 Service 连接到应用
Kubernetes 的网络模型 通过前面教程的学习,我们已经可以将容器化的应用程序在 Kubernetes 中运行起来,并且发布到 Kubernetes 内/外的网络上。 通常,Docker 使用一种 host-private 的联网方式,在此情况下,只有两个容…...

SAP ABAP 自定义表数据导入
一:效果展示: 读取 Excel 数据到 SAP 数据库表。 二:源码: *&---------------------------------------------------------------------* *& Report ZTEST_DRW02 *&----------------------------------------------------------…...

目标检测识别——大恒(DaHeng)相机操作与控制编程
文章目录 引言正文相关开发库的介绍编程准备配置引用头文件GalaxyIncludes.h配置lib文件 具体编程过程初始化和反初始化枚举设备开关设备 属性控制属性控制器种类 图像采集控制和图像处理采单帧回调采集 总结 引言 在做老师的横向项目时,需要用大恒相机,…...

国标GB28181视频监控平台EasyGBS视频无法播放,抓包返回ICMP是什么原因?
国标GB28181视频平台EasyGBS是基于国标GB/T28181协议的行业内安防视频流媒体能力平台,可实现的视频功能包括:实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。国标GB28181视频监控平台部署简单、可拓展性强,支持将…...
如何正确使用npm常用命令
npm常用命令: 官方文档:CLI Commands | npm Docs 1. npm -v:查看 npm 版本 2. npm init:初始化后会出现一个 Package.json 配置文件,可以在后面加上 -y,快速跳到问答界面 3. npm install:会…...

无人机影像配准并发布(共线方程)
无人机影像 DEM 计算四个角点坐标(刚性变换) 像空间坐标(x,y,-f) 像空间坐标畸变纠正 deltax,deltay 已知(x,y),求解(X,Y, Z)或者(Lat,Lon) 这里的Z是DEM上获取的坐标和Zs为相机坐标的高程,如果均为已…...

openGauss学习笔记-23 openGauss 简单数据管理-时间/日期函数和操作符
文章目录 openGauss学习笔记-23 openGauss 简单数据管理-时间/日期函数和操作符23.1 时间日期操作符23.2 时间/日期函数23.3 TIMESTAMPDIFF23.4 EXTRACT23.5 date_part openGauss学习笔记-23 openGauss 简单数据管理-时间/日期函数和操作符 23.1 时间日期操作符 用户在使用时…...

C++OpenCV(7):图像形态学基础操作
🔆 文章首发于我的个人博客:欢迎大佬们来逛逛 🔆 OpenCV项目地址及源代码:点击这里 文章目录 膨胀与腐蚀形态学基础 膨胀与腐蚀 膨胀与腐蚀是数学形态学在图像处理中最基础的操作。 膨胀操作是取每个位置领域内最大值࿰…...

Appium+python自动化(二十二)- 控件坐标获取(超详解)
简介 有些小伙伴或者是童鞋可能会好奇会问上一篇中的那个monkey脚本里的坐标点是如何获取的,不是自己随便蒙的猜的,或者是自己用目光或者是尺子量出来的吧,答案当然是:NO。获取控件坐标点的方式这里宏哥给小伙伴们分享和讲解三种方…...

Tensorflow benchmark 实操指南
环境搭建篇见环境搭建-CentOS7下Nvidia Docker容器基于TensorFlow1.15测试GPU_东方狱兔的博客-CSDN博客 1. 下载Benchmarks源码 从 TensorFlow 的 Github 仓库上下载 TensorFlow Benchmarks,可以通过以下命令来下载 https://github.com/tensorflow/benchmarks 我…...
【linux】调试工具介绍
文章目录 前言一、kdb二、ftrace三、gdb 前言 在Linux内核调试过程中,可以使用各种工具和技术来诊断和解决问题。以下是一些常用的Linux内核调试方法: printk:printk是Linux内核中的打印函数,可以在代码中插入打印语句来输出调试…...

2.获取DOM元素
获取DOM元素就是利用JS选择页面中的标签元素 2.1 根据CSS选择器来获取DOM元素(重点) 2.1.1选择匹配的第一个元素 语法: document.querySelector( css选择器 )参数: 包含一个或多个有效的CSS选择器 字符串 返回值: CSS选择器匹配的第一个元素,一个HTMLElement对象…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...

CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...
Android屏幕刷新率与FPS(Frames Per Second) 120hz
Android屏幕刷新率与FPS(Frames Per Second) 120hz 屏幕刷新率是屏幕每秒钟刷新显示内容的次数,单位是赫兹(Hz)。 60Hz 屏幕:每秒刷新 60 次,每次刷新间隔约 16.67ms 90Hz 屏幕:每秒刷新 90 次,…...
SQL进阶之旅 Day 22:批处理与游标优化
【SQL进阶之旅 Day 22】批处理与游标优化 文章简述(300字左右) 在数据库开发中,面对大量数据的处理任务时,单条SQL语句往往无法满足性能需求。本篇文章聚焦“批处理与游标优化”,深入探讨如何通过批量操作和游标技术提…...

五、jmeter脚本参数化
目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...