实用指南:Rust Slint实现列表式消息提示(Notification Dialog)源码分享

一、效果展示

在这里插入图片描述
在这里插入图片描述

二、源码分享

1、工程搭建

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

2、main.rs

use std::ptr::addr_eq;
use std::sync::{Arc, Mutex};
use slint::{PlatformError, ToSharedString, 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();
    let mut message: Arc<Mutex<Vec<NotificationValue>>> = Arc::new(Mutex::new(Vec::new()));
      let mut cnt = 0;
      app.global::<DataAdapter>().on_btn_clicked({
        let weak = weak.clone();
        let message = message.clone();
        move |text|{
        if let Some(strong) = weak.upgrade(){
        let adapter = strong.global::<DataAdapter>();
          cnt +=1;
          let msg = NotificationValue{
          message:format!("message {cnt}").to_shared_string(),
          timeout:3000,
          mtype:{
          if cnt == 1{
          NotificationType::Info
          }
          else if cnt == 2{
          NotificationType::Warning
          }
          else {
          cnt = 0;
          NotificationType::Error
          }
          },
          };
          message.lock().unwrap().insert(0,msg);
          adapter.set_notificationModel(slint::ModelRc::new(slint::VecModel::from(message.lock().unwrap().clone())));
          }
          }
          });
          let timer = Timer::default();
          timer.start(slint::TimerMode::Repeated, std::time::Duration::from_millis(100), {
          let weak = weak.clone();
          let message = message.clone();
          move || {
          if let Some(strong) = weak.upgrade(){
          let adapter = strong.global::<DataAdapter>();
            let mut to_remove = Vec::new();
            {
            let mut messages = message.lock().unwrap();
            for (index, item) in messages.iter_mut().enumerate() {
            if item.timeout <= 0 {
            to_remove.push(index);
            } else {
            item.timeout -= 100;
            }
            }
            }
            // 在锁外删除元素
            if !to_remove.is_empty() {
            let mut messages = message.lock().unwrap();
            for &index in to_remove.iter().rev() {
            messages.remove(index);
            }
            adapter.set_notificationModel(slint::ModelRc::new(slint::VecModel::from(messages.clone())));
            }
            }
            }
            });
            let _ = app.run();
            Ok(())
            }

3、main.slint

import { AboutSlint, VerticalBox, LineEdit, HorizontalBox, Button, GroupBox, GridBox,
ComboBox, Spinner, Slider, ListView, Palette, ProgressIndicator, CheckBox, Switch } from "std-widgets.slint";
import { DataAdapter,NotificationType,NotificationValue } from "models.slint";
export { DataAdapter}
component NotificationView inherits VerticalLayout{
width: 300px;
height: 300px;
private property <image> icon_info:@image-url("./image/icon_info.svg");
  private property <image> icon_warning:@image-url("./image/icon_warning.svg");
    private property <image> icon_error:@image-url("./image/icon_error.svg");
      ListView {
      for item[idx] in DataAdapter.notificationModel :Rectangle{
      width: 100%;
      height: 50px;
      border-radius: 15px;
      border-width: 1px;
      Rectangle {
      width: 100%;
      height: 90%;
      border-radius: 15px;
      border-width: 1px;
      background: item.mtype == NotificationType.Info ? #5abc0561 :item.mtype == NotificationType.Warning? #cad61861: #f1262661;
      HorizontalLayout {
      padding: 6px;
      Image {
      width: self.height;
      height: parent.height - parent.padding*2;
      source: item.mtype == NotificationType.Info ? icon_info :item.mtype == NotificationType.Warning? icon_warning: icon_error;
      }
      Text {
      text: item.message;
      font-size: 15px;
      color: white;
      horizontal-alignment: center;
      vertical-alignment: center;
      wrap: TextWrap.word-wrap;
      }
      }
      }
      }
      }
      }
      export component MainWindow inherits Window {
      width: 800px;
      height: 600px;
      title: "window1";
      background: #6d0bee;
      NotificationView{
      y:0;
      }
      Button {
      width: 150px;
      height: 50px;
      text: "add message";
      clicked => {
      DataAdapter.btn_clicked("ddd");
      }
      }
      }

4、models.slint

export enum  NotificationType {
Info,
Warning,
Error
}
export struct NotificationValue {
mtype:NotificationType,
message:string,
timeout:int,
}
export global DataAdapter {
in-out property <[NotificationValue]> notificationModel;
  callback btn_clicked(string);
  }

4、图片资源文件

文章顶部下载

5、工程结构

在这里插入图片描述

三、Slint库介绍

Slint(原名SixtyFPS)是一个轻量级、高性能的用户界面(UI)工具包,专为嵌入式系统、桌面应用和跨平台开发设计。它采用声明式UI编程模型,支持Rust、C++和JavaScript等语言,强调资源高效、低延迟和易用性。Slint的核心目标是简化UI开发,尤其适合资源受限环境(如微控制器)或需要高性能渲染的场景。

1、Slint的核心特性

  • 声明式UI设计:使用类似QML的语法定义UI元素,代码简洁易读。UI逻辑与业务逻辑分离,提高开发效率。
  • 跨平台支持:原生支持Linux、Windows、macOS,以及嵌入式平台(如Raspberry Pi、微控制器),无需额外适配。
  • 高性能优化:渲染引擎针对低功耗设备优化,帧率可达 60 f p s 60fps 60fps以上,内存占用极小(通常低于几MB)。
  • 响应式编程:内置数据绑定机制,UI自动更新响应状态变化,减少手动事件处理。
  • 工具链完善:提供Slint语言编译器(slintc)和IDE插件,支持实时预览和热重载。

2、在Rust中使用Slint

在Rust项目中集成Slint简单高效:

  • 安装依赖:通过Cargo添加slint crate。在Cargo.toml中添加:
    [dependencies]
    slint = "1.13.1"  # 使用最新稳定版本
  • 基本工作流
    1. 定义UI:使用slint!宏编写声明式UI代码。
    2. 编译UI:Slint编译器(slintc)将.slint文件编译为Rust代码。
    3. 集成逻辑:在Rust中绑定数据和事件处理。
  • 优势:Rust的内存安全和并发特性与Slint结合,提升UI可靠性和性能,避免常见错误如空指针或数据竞争。

3、简单示例:创建一个窗口

以下是一个基础的“Hello World”示例,展示如何在Rust中定义并运行一个Slint UI。代码结构清晰:

use slint::slint;
slint! {
// 定义UI组件
export component MainWindow inherits Window {
// 添加文本元素
Text {
text: "Hello, Slint!";
color: blue;
font-size: 24px;
}
}
}
fn main() {
// 创建并运行窗口
let window = MainWindow::new().unwrap();
window.run().unwrap();
}
  • 解释
    • slint!宏内嵌UI定义,使用类似HTML的语法。
    • export component定义可重用的UI组件,继承自Window
    • Text元素显示文本,属性如colorfont-size可动态绑定。
    • main函数初始化并运行UI,错误处理简单(unwrap用于演示,实际应更健壮)。

4、适用场景和优势

  • 嵌入式系统:低内存占用(可优化至几百KB),适合IoT设备或车载系统。
  • 桌面应用:跨平台一致性,无需Web技术栈,性能优于Electron等框架。
  • 开发效率:声明式语法减少样板代码,调试工具(如Slint Viewer)加速迭代。
  • 与其他库对比:相比GTK或Qt,Slint更轻量;相比Web框架,它提供原生性能和更少依赖。
  • 社区支持:开源项目(Apache 2.0许可证),活跃社区提供文档和示例。

5、学习资源

  • 官方文档Slint Book 提供详细教程和API参考。
  • 示例项目:GitHub仓库有丰富案例,如计算器或仪表盘应用。
  • 最佳实践:建议从简单UI开始,逐步集成复杂逻辑,利用数据绑定优化性能。

在这里插入图片描述

posted on 2025-11-12 14:21  ljbguanli  阅读(0)  评论(0)    收藏  举报