Rust Slint库达成桌面萌宠源码分享(包含拖动、右键菜单效果)

news/2025/10/3 11:08:24/文章来源:https://www.cnblogs.com/wzzkaifa/p/19124394

Rust Slint库实现桌面萌宠源码分享(包含拖动、右键菜单功能)

  • 一、效果展示
    • 1、效果展示
    • 2、源码分享
      • 2.1、工程结构
      • 2.2、main.slint
      • 2.3、models.slint
      • 2.4、main.rs
      • 2.5、Cargo.toml
  • 二、工程搭建及资源文件
    • 1、工程搭建
    • 2、资源文件
  • 三、实现原理
    • 1、Image控件介绍
      • 1.1、Image控件的基本用法
      • 1.2、支持的图片格式
      • 1.3、动态更新图片
      • 1.4、图片缩放和裁剪
      • 1.5、性能优化
    • 2、Timer介绍
      • 2.1、基本用法
      • 2.2、主要属性
      • 2.3、信号处理
      • 2.4、注意事项
    • 3、ContextMenuArea介绍
      • 3.1、核心功能
      • 3.2、基本用法
      • 3.3、注意事项

一、效果展示

1、效果展示

在这里插入图片描述

2、源码分享

2.1、工程结构

在这里插入图片描述

2.2、main.slint

import { AboutSlint, VerticalBox, LineEdit, HorizontalBox, Button, GroupBox, GridBox,
ComboBox, Spinner, Slider, ListView, Palette, ProgressIndicator, CheckBox, Switch } from "std-widgets.slint";
import { DataAdapter,Theme } from "models.slint";
export { DataAdapter ,Theme}
export component MainWindow inherits Window {
width: 100px;
height: 150px;
always-on-top: true;
no-frame: true;
background: transparent;
private property <Point> pressed_point;private property <bool> is_pressed: false;private property <int> image_cnt:0;private property <[image]> image : [@image-url("./image/0.png"),@image-url("./image/1.png"),@image-url("./image/2.png"),@image-url("./image/3.png"),@image-url("./image/4.png"),@image-url("./image/5.png"),@image-url("./image/6.png"),@image-url("./image/7.png"),@image-url("./image/8.png"),@image-url("./image/9.png"),@image-url("./image/10.png"),@image-url("./image/11.png"),@image-url("./image/12.png"),@image-url("./image/13.png"),@image-url("./image/14.png"),@image-url("./image/15.png"),@image-url("./image/16.png"),@image-url("./image/17.png"),@image-url("./image/18.png"),@image-url("./image/19.png"),@image-url("./image/20.png"),@image-url("./image/21.png"),@image-url("./image/22.png"),@image-url("./image/23.png"),@image-url("./image/24.png"),@image-url("./image/25.png"),@image-url("./image/26.png"),@image-url("./image/27.png"),@image-url("./image/28.png"),@image-url("./image/29.png"),@image-url("./image/30.png"),@image-url("./image/31.png"),@image-url("./image/32.png"),@image-url("./image/33.png"),@image-url("./image/34.png"),@image-url("./image/35.png"),@image-url("./image/36.png"),@image-url("./image/37.png"),@image-url("./image/38.png"),@image-url("./image/39.png"),@image-url("./image/40.png"),@image-url("./image/41.png"),@image-url("./image/42.png"),@image-url("./image/43.png"),@image-url("./image/44.png"),@image-url("./image/45.png"),@image-url("./image/46.png"),@image-url("./image/47.png"),@image-url("./image/48.png"),@image-url("./image/49.png"),];image := Image {width: parent.width;height: parent.height;source: @image-url("./image/0.png");image-fit: fill;image-rendering: smooth;}timer := Timer {interval: 30ms;running: false;triggered => {image.source = root.image[image_cnt];image_cnt +=1;if image_cnt >= 49 {image_cnt = 0;timer.stop();}}}TouchArea {enabled: true;pointer-event(event) => {if event.kind == PointerEventKind.move{if !timer.running {timer.start();}}if event.kind == PointerEventKind.down && event.button == PointerEventButton.left {root.is_pressed = true;root.pressed_point.x = self.mouse-x;root.pressed_point.y = self.mouse-y} else if event.kind == PointerEventKind.up && event.button == PointerEventButton.left {root.is_pressed = false;}}moved => {if(root.is_pressed){DataAdapter.position_changed((self.mouse-x - root.pressed_point.x)/1px,(self.mouse-y - root.pressed_point.y)/1px);}}}ContextMenuArea {Menu {MenuItem {title: @tr("剪切");activated => { debug("Cut"); }}MenuItem {title: @tr("复制");activated => { debug("Copy"); }}MenuItem {title: @tr("粘贴");activated => { debug("Paste"); }}MenuSeparator {}Menu {title: @tr("查找");MenuItem {title: @tr("查找下一个");}MenuItem {title: @tr("查找上一个");}}MenuSeparator {}MenuItem {title: @tr("退出");activated => { debug("quit");DataAdapter.quit_clicked();}}}}}

2.3、models.slint

export enum Theme {
Light,
Dark,
System
}
export global DataAdapter {
in-out property <string> textResValue:0;callback btn_clicked(string);callback position_changed(int, int);callback quit_clicked();}

2.4、main.rs

use slint::{PlatformError, WindowPosition};
slint::include_modules!();
use slint::{Color,Brush};
use slint::Timer;
fn main() ->Result<(), PlatformError>{let app: MainWindow  = MainWindow::new()?;let weak: slint::Weak<MainWindow> = app.as_weak();app.global::<DataAdapter>().on_btn_clicked({let weak = weak.clone();move |text|{if let Some(strong) = weak.upgrade(){let adapter = strong.global::<DataAdapter>();}}});app.global::<DataAdapter>().on_position_changed({let app = app.clone_strong();move |x:i32,y:i32|{let win = app.window();let mut pos = win.position();pos.x += x;pos.y += y;win.set_position(pos);}});app.global::<DataAdapter>().on_quit_clicked({let app = app.clone_strong();move ||{let _ = app.window().hide();}});let _ = app.run();Ok(())}

2.5、Cargo.toml

[dependencies]
slint = "1.13.1"
[build-dependencies]
slint-build = "1.13.1"

二、工程搭建及资源文件

1、工程搭建

参考我这篇文章:工程搭建详细教程

2、资源文件

在文章顶部下载

三、实现原理

主要通过ImageTimerContextMenuArea三个控件实现。

1、Image控件介绍

Image控件用于在界面中显示图片,支持多种图片格式和加载方式。

1.1、Image控件的基本用法

在Slint中,Image控件可以通过声明式语法或编程方式创建。以下是一个简单的Rust示例:

slint::slint! {
import { VerticalBox, Image } from "std-widgets.slint";
export component MainWindow inherits Window {
VerticalBox {
Image {
source: @image-url("path/to/image.png");
width: 200px;
height: 200px;
}
}
}
}

1.2、支持的图片格式

Slint的Image控件支持常见的图片格式,包括PNG、JPEG、GIF和BMP。图片可以通过文件路径、内存数据或URL加载。

1.3、动态更新图片

Image控件支持动态更新图片源。可以通过绑定到变量或回调函数实现:

slint::slint! {
export component MainWindow inherits Window {
in-out property <string> image-path: "default.png";Image {source: @image-url(image-path);}}}

1.4、图片缩放和裁剪

Image控件提供多种缩放和裁剪选项:

  • fit: 保持宽高比适应控件大小
  • fill: 拉伸填满整个控件
  • stretch: 不保持宽高比拉伸
  • tile: 平铺图片
slint::slint! {
Image {
source: @image-url("image.jpg");
image-fit: fill;
}
}

1.5、性能优化

对于频繁更新的图片,建议:

  • 使用适当大小的图片资源
  • 考虑缓存机制
  • 避免在热路径中频繁加载图片

2、Timer介绍

Timer控件是Slint中用于处理定时任务的核心组件,通常用于执行周期性任务或延迟操作。

2.1、基本用法

在Slint中,Timer控件通常通过Timer结构体或相关接口实现。以下是一个简单的示例代码:

import slint;
export component MainWindow {in property  counter: 0;callback tick;Timer {interval: 1000ms;running: true;triggered => {tick();counter += 1;}}
}

2.2、主要属性

interval
定义定时器触发的时间间隔,支持毫秒(ms)和秒(s)单位。例如1000ms1s

running
布尔值属性,控制定时器是否处于活动状态。设置为true时定时器开始运行,false时停止。

2.3、信号处理

定时器触发时会发送triggered信号,可以通过回调函数处理:

triggered()  => {// 处理定时器触发时的逻辑
}

2.4、注意事项

  1. 定时器的精度取决于底层系统实现,不可用于需要高精度计时的场景
  2. 在界面不可见时,某些平台可能会限制或暂停定时器的执行
  3. 过度使用定时器可能影响应用性能

Timer控件是Slint中处理时间相关任务的简单有效方式,适用于UI动画、定期更新等场景。

3、ContextMenuArea介绍

ContextMenuAreaslint 库中用于处理上下文菜单(右键菜单)的组件。它允许开发者为 UI 元素绑定自定义的右键菜单逻辑,提供更丰富的交互体验。

3.1、核心功能

  • 右键菜单触发:监听鼠标右键点击事件,触发自定义菜单。
  • 动态菜单内容:支持根据上下文动态生成菜单项。
  • 跨平台兼容:在支持 slint 的平台上(如 Windows、macOS、Linux)均可使用。

3.2、基本用法

export component MyComponent {in-out property  text: "Right-click me!";ContextMenuArea {Menu {MenuItem {title: "Copy";activated => { }}MenuItem {title: "Paste";activated => { }}}}
}

3.3、注意事项

  1. 移动端平台可能需要特殊处理,因为通常没有右键操作
  2. 菜单层级过深时需考虑用户体验
  3. 快捷键绑定需与系统快捷键避免冲突

在这里插入图片描述

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

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

相关文章

Redis 持久化机制 - 教程

Redis 持久化机制 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &q…

行业seo网站优化方案厦门优化公司

文章目录 背景介绍 问题描述 分析排查 解决方案 总结归纳 背景介绍 在一个嵌入式软件项目中&#xff0c;有一段使用C语言写的嵌入式代码&#xff0c;功能是把CAN总线上的几帧报文接收进来&#xff0c;并解析出数据。示例如下&#xff1a; 乍一看感觉挺简单&#xff0c;想着…

网站建站图片汉滨区住房和城乡建设局网站

在进行绘图时必须考虑这两种坐标。 世界坐标是整个区域的坐标&#xff0c;而页面坐标是可视区的坐标。这两种坐标是通过滚动条来体现出来的。 页面坐标的原点始终是窗口可视区的坐上角&#xff0c;世界坐标的原点始终不变&#xff0c;这两种坐标和VC中的屏幕坐标和客户坐标很…

2025染井吉野樱公司 TOP 种植服务推荐排行榜,染井吉野樱花苗,五公分染井吉野樱,十公分染井吉野樱,染井吉野樱批发,染井吉野樱基地,染井吉野樱花树公司推荐

引言在樱花苗木采购与景观工程实施过程中,分枝点规格的把控已成为行业突出痛点。当前市场上,染井吉野樱苗木分枝点标准混乱,从 0.5 米到 3 米不等的规格随意标注,缺乏统一规范,导致采购方难以精准匹配绿化需求。部…

网站建设如何定价广州网站制作怎样

Facebook广告是海外营销的一大利器&#xff0c;但是随着互联网的发展&#xff0c;有部分不法分子正在利用他进行盈利&#xff0c;导致Facebook官方安全审核日益严格&#xff0c;不少卖家遭遇封号问题&#xff01;这篇文章就来教你如何更好地管理 Facebook广告帐户&#xff0c;实…

如何建立自己的摄影网站做电商网站用什么框架

来源&#xff1a;AI前线 作者&#xff1a;Jiang Chen&#xff0c;Moveworks 机器学习副总裁译者&#xff1a;王强策划&#xff1a;刘燕从 Siri 到 Alexa 再到谷歌助手&#xff0c;今天我们已经被各种人工智能系统包围了。它们的设计目标只有一个&#xff1a;理解我们。我们已经…

鄂州网站建设与设计乐器网站模板

windows2003-建立域 Active Directory建立DNS建立域查看日志xp 加入域 Active Directory 活动目录是一个包括文件、打印机、应用程序、服务器、域、用户账户等对象的数据库。 常见概念&#xff1a;对象、属性、容器 域组件&#xff08;Domain Component&#xff0c;DC&#x…

glazewm_windows平铺窗口管理器使用方法

1.在github上寻找预构建版本 2.双击安装 3.关闭与zebra有关的命令 配置文件在 C:\Users{yourname}.glzr\glazewm\config.yaml 打开这个文件 默认这条指令是没有注释的,我这边直接注释掉这样软件启动就不会报错了4.添加…

详细介绍:LeetCode热题100(1-7)

详细介绍:LeetCode热题100(1-7)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco&…

树莓派搭建NAS之三:使用OpenList挂载网盘

移动硬盘中发现有之前备份的文件,并且监控是一直在写盘,容易将磁盘写坏,之前备份的数据就无法读出。找了半天找到了个不用的32GB的U盘,可以先用着。 U盘的空间太小,连续录制1-2天的时间就会满了,之前的监控也无法…

sg-ss 逆向分析

sg-ss、sgss声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! wx a15018601872 q 27…

网站建设报价比较深圳团购网站设计

在前端Web开发中&#xff0c;下拉筛选功能是一种非常常见的交互方式&#xff0c;它可以帮助用户快速选择所需的选项。本文将介绍如何利用Vue.js和uni-app框架来实现一个高效的下拉筛选功能。通过使用这两个强大的前端框架&#xff0c;我们可以轻松地创建具有响应式用户操作的下…

PySide6 之登录界面设计

一、效果图二、示例代码from PySide6.QtWidgets import QApplication, QWidget from PySide6.QtCore import Qt, Slot, QPoint, QPropertyAnimation, QEasingCurve from PySide6.QtGui import QColorfrom views.login…

Jupyter notebook 虚拟环境(服务)EnvironmentLocationNotFound: Not a conda environment

ErrorAn error occurred while retrieving installed packages. EnvironmentLocationNotFound: Not a conda environment: E:\Eprogramfiles\Anaconda3\envs\Anaconda3 ================================ 网上说修改文…

本地部署overleaf服务帮助latex论文编写 —— 操作笔记

本地部署overleaf服务帮助latex论文编写 —— 操作笔记原文参照: https://www.cnblogs.com/xuhe2/p/18792632操作: git clone https://github.com/xuhe2/sharelatex-ce本博客是博主个人学习时的一些记录,不保证是为…

简述网站开发的三层架构中国建设银行网站转账

近用到Java动态生成背景透明的图片功能&#xff0c;从gif和png中选择了png格式&#xff0c;个中缘由就不说了&#xff0c;于是动手到网上搜索有用的代码。现把搜索结果总结如下&#xff1a;1. 生成png图片int width 400;int height 300;// 创建BufferedImage对象BufferedImag…

怎么免费建立网站广告设计制作公司简介

1. 张量概念 张量本质上是一个n维数组&#xff0c;它在numpy中为ndarray, 在pytorch中称为tensor &#xff0c; 两者的区别在于&#xff1a; numpy仅支持CPU计算tensor能支持GPU运算&#xff0c;并且支持自动微分&#xff0c;更适合深度学习 2. 张量的访问 一个二维矩阵a&a…

【Groovy】Array、List、Set、Map简介

1 Array 1.1 创建数组 1.1.1 创建一维数组 int[] arr1 = new int[2] arr1[0] = 1 arr1[1] = 2float[] arr2 = new float[] { 1f, 2f, 3f } String[] arr3 = ["abc", "xyz"] as String[]1.1.2 创建…

深入解析:【Python高级语法与正则表达式】

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

成都 广告公司网站建设成都建设路小学网站

系统架构师考试是对计算机从业人员&#xff0c;以考代评的重要考试&#xff0c;近几年一直在参加考试&#xff0c;屡战屡败&#xff0c;后又屡败屡战&#xff0c;记录总结论文相关的知识点&#xff0c;方便考前查看。 一、2010年论文 1&#xff09;论软件的静态演化和动态演化…