Rust 使用egui创建一个简单的下载器demo

仓库连接: https://github.com/GaN601/egui-demo-download-util
这是我第一个rust gui demo, 学习rust有挺长时间了, 但是一直没有落实到实践中, 本着对桌面应用的兴趣, 考察了slint、egui两种框架, 最后还是选择了egui.

这篇博客同时包含我当前的一些理解, 但是自身技术有限, 可能有不少错误的地方. 有意者请在评论区指正.

这个demo的效果就是通过主窗口的按钮, 呼出子窗口的输入框, 点击下载按钮后就可以下载文件, 因为只是demo, 下载功能不详细, 只是用reqwest请求下载了而已.

egui要求我们创建一个自己的结构体来进行状态保存, 因此我们需要以下结构体:
点击查看结构体

#[derive(Default)]
struct MainWindow {
    window_download_url: DownloadUrl,
}
#[derive(Default, Clone)]
pub struct DownloadUrl {
    pub is_show: bool,
    pub is_start: bool,
    pub url: String,
    pub local_path: String,
}
 
impl DownloadUrl {
    pub fn show_window(&mut self, ctx: &Context) {
        let _ = Window::new("Download Url")
            .open(&mut self.is_show.clone())
            .show(ctx, |ui| {
        // 这里在为下载窗口添加一些ui元素
                ui.heading("Download Url");
                ui.text_edit_singleline(&mut self.url);
                ui.text_edit_singleline(&mut self.local_path);
        // 这里将用户输入的数据保存在MainWindow中, 这样当我们点击下载按钮时就会开始下载文件
                if ui.button("Select Folder").clicked() {
                    if let Some(path) = rfd::FileDialog::new().pick_folder() {
                        self.local_path = path.display().to_string();
                    }
                }
        // 关闭当前窗口. 因为是即时模式, 因此下一帧这个窗口不会出现. 我们只需要修改布尔值即可.
                if ui.button("Download").clicked() {
                    self.is_show = false;
                    self.is_start = true;
                }
            });
    }

}

点击查看项目依赖

egui = "0.19.0"
eframe = "0.19.0"
reqwest = "0.11.12"
tokio = { version = "1.21.2" , features=["full"]}

rfd = "0.10.0"

点击查看项目代码

use eframe::{run_native, App, Frame, NativeOptions};
use egui::{CentralPanel, Context};
use std::fs::File;
use std::io::Write;
use std::path::Path;
 
//首先使用tokio的main方法
#[tokio::main]
async fn main() {
    println!("Hello, world!");
    let option = NativeOptions {
    // 定义窗口大小
        initial_window_size: Some(egui::vec2(640.0, 480.0)),
        ..Default::default()
    };
    // 启动egui的主窗口, MainWindow就是我们保持状态的结构体
    run_native(
        "egui download util",
        option,
        Box::new(|_c| Box::<MainWindow>::default()),
    );
}
// 实现App Trait, 因为egui是即时模式, 因此状态数据只能从self(MainWindow)拿
impl App for MainWindow {
    fn update(&mut self, ctx: &Context, frame: &mut Frame) {
    // 这里是创建了一个面板, 并且面板里有一个下载的按钮, 当点击按钮后, 会展示一个子窗口
        CentralPanel::default().show(ctx, |ui| {
            if ui.button("Download").clicked() {
                self.window_download_url.is_show = true;
            }
        });
 
        if self.window_download_url.is_show {
            self.window_download_url.show_window(ctx);
        }
 
    // 在这里开始执行下载文件的逻辑, 因为所有权问题, 因此我直接clone了这个结构
        let url = &mut self.window_download_url;
        let target = url.clone();
 
        if !(target.url.is_empty() || target.local_path.is_empty()) && url.is_start {
            url.is_start = false;
            tokio::spawn(async move {
        // 执行下载文件的逻辑, 失败的处理感觉没啥必要, 其实可以考虑出个dialog
                download_file_to_local_path(&target)
                    .await
                    .expect("TODO: panic message");
            });
        }
    }
}
 
async fn download_file_to_local_path(
    target: &DownloadUrl,
) -> Result<(), Box<dyn std::error::Error>> {
// 获取文件夹路径选择器的路径, 因为不打算太精细, 就直接生成了当前时间戳的文件名, 连文件后缀都不给.
    let file_path = Path::new(&target.local_path).join(
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis()
            .to_string(),
    );
 
    let mut file = File::create(file_path)?;
    let response = reqwest::get(&target.url).await?;
    // 写入文件, 下载文件逻辑完成
    file.write_all(&response.bytes().await?)?;
 
    Ok(())
}

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

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

相关文章

Java 7大排序

&#x1f435;本篇文章将对数据结构中7大排序的知识进行讲解 一、插入排序 有一组待排序的数据array&#xff0c;以升序为例&#xff0c;从第二个数据开始&#xff08;用tmp表示&#xff09;依次遍历整组数据&#xff0c;每遍历到一个数据都再从tmp的前一个数据开始&#xff0…

LeetCode-2960. 统计已测试设备【数组 模拟】

LeetCode-2960. 统计已测试设备【数组 模拟】 题目描述&#xff1a;解题思路一&#xff1a;模拟解题思路二&#xff1a; 一次遍历&#xff0c;简洁写法解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个长度为 n 、下标从 0 开始的整数数组 batteryPercentages &#xf…

自动驾驶纵向控制算法

本文来源——b站忠厚老实的老王&#xff0c;链接&#xff1a;忠厚老实的老王投稿视频-忠厚老实的老王视频分享-哔哩哔哩视频 (bilibili.com)&#xff0c;侵删。 功率和转速之间的关系就是&#xff1a;功率P等于转矩M乘以转速ω。并不是油门越大加速度就越大。 发动机和电机的转…

AngularJS基本概念

版本&#xff1a; AngularJs 1.x&#xff1a;https://angularjs.org/ AngularJs 2&#xff1a;https://angular.io/ 或 https://angular.cn/ 实现语言&#xff1a; Angular 1.x&#xff1a;使用ES(avaScript)编写&#xff0c;可直接在浏览器中运行。 Angular 2&#xff1a…

【机器学习】AI时代的核心驱动力

机器学习&#xff1a;AI时代的核心驱动力 一、引言二、机器学习的基本原理与应用三、机器学习算法概览四、代码实例&#xff1a;线性回归的Python实现 一、引言 在数字化浪潮席卷全球的今天&#xff0c;人工智能&#xff08;AI&#xff09;已经不再是科幻小说中的遥远概念&…

[muduo网络库]——muduo库三大核心组件之Channel类(剖析muduo网络库核心部分、设计思想)

接着上文[muduo网络库]——muduo库的Reactor模型&#xff08;剖析muduo网络库核心部分、设计思想&#xff09;&#xff0c;接下来详细介绍一下这三大核心组件中的Channel类。 先回顾一下三大核心组件之间的关系。 接着我们进入正题。 Channel Channel类封装了一个 fd 、fd感兴…

【STM32 |程序实测】LED灯闪烁、LED灯流水线、蜂鸣器

LED闪烁&LED流水灯&蜂鸣器的面包板接线图&#xff0c;及对应程序示例 LED闪烁 面包板接线图如下 开启APB2时钟&#xff0c;并且在GPIOA上进行配置&#xff0c;推挽输出&#xff0c;引脚A0&#xff0c;50HZ速度 #include "stm32f10x.h" /…

[Linux][网络][网络层][IP协议]详细讲解

目录 0.基本概念1.IP协议头格式2.IP分片与组装1.为什么要分片&#xff1f;2.分片后谁来组装&#xff1f;3.这个分片操作传输层知道吗&#xff1f;4.如何识别报文和报文的不同&#xff1f;5.接收端&#xff0c;如何得知报文是独立的还是一个分片&#xff1f;6.如何区别哪些分片是…

【论文泛读|附源码】如何进行动力学重构? 神经网络自动编码器结合SINDy发现数据背后蕴含的方程

这一篇文章叫做 数据驱动的坐标发现与方程发现算法。 想回答的问题很简单&#xff0c;“如何根据数据写方程”。 想想牛顿的处境&#xff0c;如何根据各种不同物体下落的数据&#xff0c;写出万有引力的数学公式的。这篇文章就是来做这件事的。当然&#xff0c;这篇论文并没有…

数据结构--图。

在前面&#xff0c;我们学习了线性表和树&#xff0c;而接下来我们要学习的图相较于他们就更加复杂。 目录 一.图的有关概念 一.图的有关概念 1.定义 图(graph)G由两个集合V和E组成&#xff0c;记为G&#xff08;VE)。V是顶点的有穷非空集合;E是边的集合,边是V中顶点的无序对…

【Linux】传输文件,补充:VMware中Linux系统无法连接网络的解决方法

Linux系统可以和其他系统之间进行传输文件&#xff0c;只要通过ssh连接成功以后&#xff0c;就能进行文件传输。 Linux系统也可以通过URL规则和网页之间进行传输文件&#xff08;即上传/下载&#xff09;。 1、Linux系统之间传输文件&#xff1a;scp centos7自带ssh服务&…

FPGA+炬力ARM实现VR视频播放器方案

FPGA炬力ARM方案&#xff0c;单个视频源信号&#xff0c;同时驱动两个LCD屏显示&#xff0c;实现3D 沉浸式播放 客户应用&#xff1a;VR视频播放器 主要功能&#xff1a; 1.支持多种格式视频文件播放 2.支持2D/3D 效果实时切换播放 3.支持TF卡/U盘文件播放 4.支持定制化配置…

36.Docker-Dockerfile自定义镜像

镜像结构 镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。 镜像是分层机构&#xff0c;每一层都是一个layer BaseImage层&#xff1a;包含基本的系统函数库、环境变量、文件系统 EntryPoint:入口&#xff0c;是镜像中应用启动的命令 其他&#xff1a;在…

QT-小项目:连接MY SQL数据库实现登录(下一章实现登录注册账号和忘记密码功能)

一、环境准备 1、下载MYSQL 64位&#xff0c;安装完成&#xff0c;制作简易数据库教程如下&#xff1a; MY SQL安装 2、QT 编译器使用 二、实现工程目录&#xff08;基于上一章基础上&#xff09; 三、源程序增加内容如下&#xff1a; login.cpp 增加头文件&#xff1a; #in…

《TAM》论文笔记(上)

原文链接 [2005.06803] TAM: Temporal Adaptive Module for Video Recognition (arxiv.org) 原文代码 GitHub - liu-zhy/temporal-adaptive-module: TAM: Temporal Adaptive Module for Video Recognition 原文笔记 What&#xff1a; TAM: Temporal Adaptive Module for …

内网安全综合管理系统是什么 | 好用的内网安全管理系统有哪些

内网安全综合管理系统是指一种集成终端管理、网络管理、内容管理、资产管理等功能的综合性安全管理系统。它主要对内网上的主机进行统一安全管理&#xff0c;包括对网络主机用户操作实施监督控制&#xff0c;并对主机中的安全软件&#xff08;如主机入侵监测系统、主机防火墙和…

5 Spring 事务管理

目录 1.概述 2.事务特性&#xff1a;ACID 3.Spring 框架的事务管理支持两种方式 编程式事务 申明式事务 4.Spring 事务管理 API 事务管理器接口 Spring 的回滚方式 事务定义接口 事务的四种隔离级别 事务的七种传播行为 5.事务注解例子&#xff1a; Transactianal…

springboot+vue+mybatis警情高发智能灯箱+PPT+论文+讲解+售后

时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;警情高发智能灯箱当然不能排除在外。警情高发智能灯箱是在实际应用和软件工程的开发原理之上&#xff0c;运用微信开发者、java语言以及SpringBo…

python:做柱状图

import matplotlib.pyplot as plt # 数据 categories [A, B, C, D] values [23, 45, 56, 78] # 创建柱状图 plt.bar(categories, values) # 添加标题和标签 plt.title(柱状图示例) plt.xlabel(类别) plt.ylabel(数值) # 显示图形 plt.show() D:\software\新建文件夹\python\L…

力扣每日一题- 给植物浇水 II -2024.5.9

力扣题目&#xff1a;给植物浇水 II 题目链接: 2105.给植物浇水 II 题目描述 代码思路 根据题目内容&#xff0c;使用双指针从左右两边同时向中间移动&#xff0c;模拟浇水过程即可。 代码纯享版 class Solution {public int minimumRefill(int[] plants, int capacityA, …