当前位置: 首页 > news >正文

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: &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();}
}

相关文章:

rust gtk 桌面应用 demo

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

《嵌入式 - 工具》J-link读写MCU内部Flash

1 J-Link简介 J-Link是SEGGER公司为支持仿真ARM内核芯片推出的JTAG仿真器。配合IAR EWAR&#xff0c;ADS&#xff0c;KEIL&#xff0c;WINARM&#xff0c;RealView等集成开发环境支持所有ARM7/ARM9/ARM11,Cortex M0/M1/M3/M4, Cortex A5/A8/A9等内核芯片的仿真&#xff0c;是学…...

算法练习-LeetCode1071. Greatest Common Divisor of Strings

题目地址&#xff1a;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里使用

问题发生 协同开发的过程中&#xff0c;同时在dotnet里面添加了nuget的grpc包&#xff0c;在不清楚的情况下执行自动生成脚本&#xff0c;下载nuget包失败&#xff0c;说是权限不足&#xff0c;于是就使用了sudo进行自动生成&#xff0c;结果在下一次重新打包的过程中&#xff…...

软件测试技能大赛环境搭建及系统部署报告

环境搭建及系统部署报告 环境搭建与配置过程&#xff08;附图&#xff09; JDK环境变量配置截图 【截取JDK环境变量配置截图】 查看JDK版本信息截图 【截取使用命令查看JDK版本信息截图&#xff0c;必须截取查看信息成功截图】 root账号成功登录MySQL截图 【截取使用root账…...

浅谈现代通信技术

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

windows环境下adb 下载和配置,连接手机。

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

[STL]list使用介绍

[STL]list使用 注&#xff1a;本文测试环境是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 的网络模型 通过前面教程的学习&#xff0c;我们已经可以将容器化的应用程序在 Kubernetes 中运行起来&#xff0c;并且发布到 Kubernetes 内/外的网络上。 通常&#xff0c;Docker 使用一种 host-private 的联网方式&#xff0c;在此情况下&#xff0c;只有两个容…...

SAP ABAP 自定义表数据导入

一:效果展示&#xff1a; 读取 Excel 数据到 SAP 数据库表。 二&#xff1a;源码&#xff1a; *&---------------------------------------------------------------------* *& Report ZTEST_DRW02 *&----------------------------------------------------------…...

目标检测识别——大恒(DaHeng)相机操作与控制编程

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

国标GB28181视频监控平台EasyGBS视频无法播放,抓包返回ICMP是什么原因?

国标GB28181视频平台EasyGBS是基于国标GB/T28181协议的行业内安防视频流媒体能力平台&#xff0c;可实现的视频功能包括&#xff1a;实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。国标GB28181视频监控平台部署简单、可拓展性强&#xff0c;支持将…...

如何正确使用npm常用命令

npm常用命令&#xff1a; 官方文档&#xff1a;CLI Commands | npm Docs 1. npm -v&#xff1a;查看 npm 版本 2. npm init&#xff1a;初始化后会出现一个 Package.json 配置文件&#xff0c;可以在后面加上 -y&#xff0c;快速跳到问答界面 3. npm install&#xff1a;会…...

无人机影像配准并发布(共线方程)

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

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):图像形态学基础操作

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

Appium+python自动化(二十二)- 控件坐标获取(超详解)

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

Tensorflow benchmark 实操指南

环境搭建篇见环境搭建-CentOS7下Nvidia Docker容器基于TensorFlow1.15测试GPU_东方狱兔的博客-CSDN博客 1. 下载Benchmarks源码 从 TensorFlow 的 Github 仓库上下载 TensorFlow Benchmarks&#xff0c;可以通过以下命令来下载 https://github.com/tensorflow/benchmarks 我…...

【linux】调试工具介绍

文章目录 前言一、kdb二、ftrace三、gdb 前言 在Linux内核调试过程中&#xff0c;可以使用各种工具和技术来诊断和解决问题。以下是一些常用的Linux内核调试方法&#xff1a; printk&#xff1a;printk是Linux内核中的打印函数&#xff0c;可以在代码中插入打印语句来输出调试…...

2.获取DOM元素

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

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

云安全与网络安全:核心区别与协同作用解析

在数字化转型的浪潮中&#xff0c;云安全与网络安全作为信息安全的两大支柱&#xff0c;常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异&#xff0c;并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全&#xff1a;聚焦于保…...

基于单片机的宠物屋智能系统设计与实现(论文+源码)

本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢&#xff0c;连接红外测温传感器&#xff0c;可实时精准捕捉宠物体温变化&#xff0c;以便及时发现健康异常&#xff1b;水位检测传感器时刻监测饮用水余量&#xff0c;防止宠物…...

解析“道作为序位生成器”的核心原理

解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制&#xff0c;重点解析"道作为序位生成器"的核心原理与实现框架&#xff1a; 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...