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

Flutter桌面应用程序定义系统托盘Tray

文章目录

  • 概念
  • 实现方案
    • 1. tray_manager
      • 依赖库
      • 支持平台
      • 实现步骤
    • 2. system_tray
      • 依赖库
      • 支持平台
      • 实现步骤
    • 3. 两种方案对比
    • 4. 注意事项
    • 5. 话题拓展

概念

系统托盘:系统托盘是一种用户界面元素,通常出现在操作系统的任务栏或桌面顶部。它是一个水平的狭长区域,用于显示各种图标和通知,以提供快速访问和操作特定应用程序或系统功能。系统托盘通常包含操作系统或第三方应用程序的图标,这些图标可以显示有关应用程序状态、提醒和通知等信息。用户可以通过单击这些图标来打开应用程序的主窗口、执行特定功能或查看详细信息。系统托盘的设计旨在提供一种方便的方式来管理和访问常用的应用程序和系统功能,以提高用户的工作效率。
效果展示
在这里插入图片描述

作为现代操作系统中常见的一个组件,系统托盘能够让用户方便地访问常用的应用程序或者系统功能。对于Flutter桌面应用程序开发者来说,如何在应用程序中定义系统托盘是一个值得探讨的问题。本文将简介系统托盘的概念,并介绍两种可用的Flutter桌面应用程序系统托盘方案。

实现方案

1. tray_manager

依赖库

tray_manager

支持平台

Windows, macOS & Linux

实现步骤

  1. 在pubspec.yaml中添加依赖
dependencies:...tray_manager: ^0.2.0
  1. 导入依赖
import 'package:flutter/material.dart' hide MenuItem;
import 'package:tray_manager/tray_manager.dart';
  1. 配置系统托盘特性
Future<void> _init() async {//设置系统托盘图标,Windows图标必须文件后缀必须是.icoawait trayManager.setIcon(Platform.isWindows? 'assets/images/tray_icon_original.ico': 'assets/images/img_1.png',);//设置系统托盘的标题trayManager.setTitle("system tray");//设置系统托盘的标题trayManager.setToolTip("How to use system tray with Flutter:鼠标滑过提示");//设置系统托盘的菜单Menu menu = Menu(items: [//设置系统托盘的子菜单MenuItem.submenu(// key key: 'window_settings',label: '窗口设置',//trayManager 不支持菜单项添加图标,该配置无效icon: Platform.isWindows? 'assets/images/app_icon.bmp': 'assets/images/img_1.png',submenu: Menu(items: [MenuItem.checkbox(checked: true,label: "毛玻璃效果",onClick: (MenuItem menuItem) {menuItem.checked = !(menuItem.checked == true);if (kDebugMode) {print("毛玻璃效果 onClick ${menuItem.checked}");}},),MenuItem.checkbox(checked: true,label: "窗口置顶",onClick: (MenuItem menuItem) {menuItem.checked = !(menuItem.checked == true);if (kDebugMode) {print("窗口置顶 onClick ${menuItem.checked}");}},),MenuItem.checkbox(checked: true,label: "自启动",onClick: (MenuItem menuItem) {menuItem.checked = !(menuItem.checked == true);if (kDebugMode) {print("自启动 onClick ${menuItem.checked}");}},),//可选类型的菜单栏MenuItem.checkbox(checked: true,label: "图标闪烁",onClick: (MenuItem menuItem) {menuItem.checked = !(menuItem.checked == true);if (kDebugMode) {print("图标闪烁 onClick ${menuItem.checked}");}},),])),//分割线MenuItem.separator(),MenuItem(key: 'open_app',label: 'Open App',onClick: (MenuItem menuItem) {}),MenuItem(key: 'exit_app',label: 'Exit App',onClick: (MenuItem menuItem) {}),],);if (kDebugMode) {print("menu:${menu.toJson()}");}//为系统托盘配置菜单await trayManager.setContextMenu(menu);
}
  1. 监听TrayListener
import 'package:flutter/material.dart';
import 'package:tray_manager/tray_manager.dart';class HomePage extends StatefulWidget {_HomePageState createState() => _HomePageState();
}class _HomePageState extends State<HomePage> with TrayListener {void initState() {trayManager.addListener(this);super.initState();_init();}void dispose() {trayManager.removeListener(this);super.dispose();}void _init() {// ...}Widget build(BuildContext context) {// ...}
//未触发该事件
void onTrayIconRightMouseUp() {// TODO: implement onTrayIconRightMouseUpsuper.onTrayIconRightMouseUp();if (kDebugMode) {print("onTrayIconMouseUp");}
}//未触发该事件

void onTrayIconMouseUp() {super.onTrayIconMouseUp();if (kDebugMode) {print("onTrayIconMouseUp");}
}

void onTrayIconMouseDown() {if (kDebugMode) {print("onTrayIconMouseDown");}//弹出托盘的菜单栏trayManager.popUpContextMenu();
}
void onTrayIconRightMouseDown() {if (kDebugMode) {print("onTrayIconRightMouseDown");}//弹出托盘的菜单栏trayManager.popUpContextMenu();
}//弹出托盘的菜单栏点击事件

void onTrayMenuItemClick(MenuItem menuItem) {if (kDebugMode) {print("menuItem:${menuItem.key}-${menuItem.label}");}
}
}

2. system_tray

依赖库

system_tray

支持平台

Windows, macOS & Linux

实现步骤

  1. 在pubspec.yaml中添加依赖
dependencies:...system_tray: ^2.0.3
  1. 导入依赖
import 'package:system_tray/system_tray.dart';
  1. 配置系统托盘特性
//创建SystemTray 对象
final SystemTray _systemTray = SystemTray();
Timer? _timer;//配置系统托盘
Future<void> _initSystemTray() async {//设置系统托盘的图标,必须是.ico后缀的图片await _systemTray.initSystemTray(iconPath: Platform.isWindows? 'assets/images/tray_icon_original.ico': 'assets/images/img_1.png',);//设置系统托盘的标题_systemTray.setTitle("system tray");//设置系统托盘的提示_systemTray.setToolTip("How to use system tray with Flutter");//注册系统托盘事件_systemTray.registerSystemTrayEventHandler((eventName) {debugPrint("eventName: $eventName");//注册系统托盘事件:点击事件if (eventName == kSystemTrayEventClick) {//Windows系统:显示主窗口   其他系统弹出托盘菜单弹框Platform.isWindows? windowManager.show(): _systemTray.popUpContextMenu();//注册系统托盘事件:鼠键右键} else if (eventName == kSystemTrayEventRightClick) {//Windows系统:弹出托盘菜单弹框  其他系统: 显示主窗口Platform.isWindows? _systemTray.popUpContextMenu(): windowManager.show();}});//创建托盘的菜单final Menu _menuMain = Menu();await _menuMain.buildFrom([//创建子菜单SubMenu(label: "窗口设置",//创建为菜单子项添加图标,格式必须是bmpimage: Platform.isWindows? 'assets/images/app_icon.bmp': 'assets/images/img_1.png',children: [//创建可选框类型的菜单项MenuItemCheckbox(label: "毛玻璃效果",checked: true,name: 'acrylic_cb',onClicked: (MenuItemBase menuItem) async {//更新MenuItemCheckbox的状态await menuItem.setCheck(!menuItem.checked);if (kDebugMode) {print("毛玻璃效果 onClick ${menuItem.checked}");}if (menuItem.checked == true) {showAcrylic(color);} else {closeAcrylic();}}),MenuItemCheckbox(label: "窗口置顶",checked: true,onClicked: (MenuItemBase menuItem) async {await menuItem.setCheck(!menuItem.checked);if (kDebugMode) {print("窗口置顶 onClick ${menuItem.checked}");}if (menuItem.checked == true) {windowManager.setAlwaysOnTop(true);} else {windowManager.setAlwaysOnTop(false);}}),MenuItemCheckbox(label: "自启动",checked: true,name: 'auto_start_cb',onClicked: (MenuItemBase menuItem) async {// menuItem.checked = !(menuItem.checked == true);await menuItem.setCheck(!menuItem.checked);if (kDebugMode) {print("自启动 onClick ${menuItem.checked}");}}),MenuItemCheckbox(label: "图标闪烁",checked: true,name: "flash_cb",onClicked: (MenuItemBase menuItem) async {MenuItemCheckbox? flashCb =_menuMain.findItemByName<MenuItemCheckbox>("flash_cb");await flashCb?.setCheck(!menuItem.checked);if (kDebugMode) {print("图标闪烁 onClick ${menuItem.checked}");}if (menuItem.checked) {startFlashIcon();} else {stopFlashIcon();}}),]),//菜单分割线MenuSeparator(),//菜单项MenuItemLabel(label: 'Open App',image: Platform.isWindows? 'assets/images/app_icon.bmp': 'assets/images/img_1.png',onClicked: (MenuItemBase menuItem) {windowManager.show();}),MenuItemLabel(label: 'Exit App',image: Platform.isWindows? 'assets/images/app_icon.bmp': 'assets/images/img_1.png',onClicked: (MenuItemBase menuItem) {windowManager.close();}),]);if (kDebugMode) {print("menu:${_menuMain.toString()}");}//为系统托盘设置菜单项await _systemTray.setContextMenu(_menuMain);
}
  1. 完整代码
import 'package:flutter/material.dart';
import 'package:tray_manager/tray_manager.dart';class HomePage extends StatefulWidget {_HomePageState createState() => _HomePageState();
}class _HomePageState extends State<HomePage>  {Timer? _timer;final SystemTray _systemTray = SystemTray();void initState() {super.initState();_initSystemTray();}void dispose() {_timer.cancel();super.dispose();}void _initSystemTray() {// ...}//开始图标闪烁
void startFlashIcon() {if (kDebugMode) {print("startFlashIcon");}var imageList = const ["assets/images/tray_icon_original.ico","assets/images/tray_icon.ico"];var index = 0;_timer =Timer.periodic(const Duration(milliseconds: 500), (Timer timer) async {if (kDebugMode) {print("path:${imageList[index]}");}await _systemTray.setImage(imageList[index]);index = (index == 0) ? 1 : 0;});
}//停止图标闪烁
void stopFlashIcon() async {if (kDebugMode) {print("stopFlashIcon");}_timer?.cancel();_timer = null;await _systemTray.setImage("assets/images/tray_icon_original.ico");
}Widget build(BuildContext context) {// ...}
}

3. 两种方案对比

   system_tray 支持菜单项添加图标,tray_manager不支持菜单项添加图标

4. 注意事项

Windows平台系统托盘图标需要是以.ico后缀的图片,菜单项图标需要是.bmp后缀的图片,否则图片无法显示;

5. 话题拓展

  • BMP格式(Bitmap):BMP是一种无损的位图图像格式,最初由Microsoft开发。它可以存储图像的像素颜色和位置信息,并支持不同的色彩深度。BMP文件通常较大,因为它们不经过压缩,保留了图像的每个像素的完整信息。BMP格式适用于Windows系统和一些图像编辑软件。
  • ICO格式(Icon):ICO是一种用于存储图标的文件格式。ICO文件通常用于表示计算机系统上的各种图标,例如文件夹、应用程序和网站等的图标。ICO文件可以包含多个图标大小和颜色深度的版本,以适应不同的显示需求。ICO文件可以在Windows系统中直接使用,也可以在网页或应用程序中使用。

相关文章:

Flutter桌面应用程序定义系统托盘Tray

文章目录 概念实现方案1. tray_manager依赖库支持平台实现步骤 2. system_tray依赖库支持平台实现步骤 3. 两种方案对比4. 注意事项5. 话题拓展 概念 系统托盘&#xff1a;系统托盘是一种用户界面元素&#xff0c;通常出现在操作系统的任务栏或桌面顶部。它是一个水平的狭长区…...

docker:安装mysql以及最佳实践

文章目录 1、拉取镜像2、运行容器3、进入容器方式一方式二方式三容器进入后连接mysql和在宿主机连接mysql的区别 持久化数据持久化数据最佳实践 1、拉取镜像 docker pull mysql2、运行容器 docker run -d -p 3307:3306 --name mysql-container -e MYSQL_ROOT_PASSWORD123456 …...

uniapp实战 —— 自定义顶部导航栏

效果预览 下图中的红框区域 范例代码 src\pages.json 配置隐藏默认顶部导航栏 "navigationStyle": "custom", // 隐藏默认顶部导航src\pages\index\components\CustomNavbar.vue 封装自定义顶部导航栏的组件&#xff08;要点在于&#xff1a;获取屏幕边界…...

中国移动频段划分

1、900MHz&#xff08;Band8&#xff09;上行&#xff1a;889-904MHz&#xff0c;下行&#xff1a;934-949MHz&#xff0c;带宽共计15MHz&#xff0c;目前部署&#xff1a;2G/NB-IoT/4G 2、1800MHz&#xff08;Band3&#xff09;上行&#xff1a;1710-1735MHz&#xff0c;下行…...

《PySpark大数据分析实战》-01.关于数据

&#x1f4cb; 博主简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是wux_labs。&#x1f61c; 热衷于各种主流技术&#xff0c;热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员&#xff08;PCTA&#xff09;、TiDB数据库专家&#xff08;PCTP…...

Qt/C++视频监控拉流显示/各种rtsp/rtmp/http视频流/摄像头采集/视频监控回放/录像存储

一、前言 本视频播放组件陆陆续续写了6年多&#xff0c;一直在持续更新迭代&#xff0c;视频监控行业客户端软件开发首要需求就是拉流显示&#xff0c;比如给定一个rtsp视频流地址&#xff0c;你需要在软件上显示实时画面&#xff0c;其次就是录像保存&#xff0c;再次就是一些…...

Vue.js - 界面设计工具和UI组件库

ViewDesign ViewDesign是一款开源的在线设计工具&#xff0c;它主要提供了一种可视化的界面设计方法&#xff0c;可以帮助设计师和开发人员更高效地完成界面设计和开发工作。 ViewDesign的特点是支持在线协作&#xff0c;可以多人同时进行设计&#xff0c;提高了设计效率&…...

【贪心算法】 Opponents

这道题写伪代码就好了&#xff01; Description Arya has n opponents in the school. Each day he will fight with all opponents who are present this day. His opponents have some fighting plan that guarantees they will win, but implementing this plan requires pr…...

【git 相关操作】

git status - 查看当前状态 git add - 将文件添加到暂存区 git commit -m "msg" - 提交暂存区文件到本地仓库 git push origin master - 本地仓库文件推送到远程仓库 git merge - 合并分支 git clone - 从指定地址克隆项目 git log - 查看commit日志 git stash push …...

流媒体音视频/安防视频云平台/可视化监控平台EasyCVR无法启动且打印panic报错,是什么原因?

国标GB视频监控管理平台/视频集中存储/云存储EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等。AI智能大数据视频分析EasyCVR平台已经广泛应用在工地、工厂、园…...

H264之NALU结构详解

摘要&#xff1a;本文详细描述了AVC的NALU的码流结构&#xff0c;以及各个层面上NALU详细的构成。   关键字&#xff1a;AVC&#xff0c;NALU 1 NALU简介 NAL层即网络抽象层&#xff08;Network Abstraction Layer&#xff09;&#xff0c;是为了方便在网络上传输的一种抽象…...

快速整合EasyExcel实现Excel的上传下载

1.EasyExcel 2.Excel的上传&#xff08;读Excel&#xff09; 3.Excel的下载&#xff08;写Excel&#xff09; 4.结语 1.EasyExcel 首先&#xff0c;这里给出EasyExcel的官方文档&#xff1a;https://easyexcel.opensource.alibaba.com/ alibaba.com不用我多说了吧&#xff0c;大…...

MongoDB的条件操作符

本文主要介绍MongoDB的条件操作符。 目录 MongoDB条件操作符1.比较操作符2.逻辑操作符3.元素操作符4.数组操作符5.文本搜索操作符 MongoDB条件操作符 MongoDB的条件操作符主要分为比较操作符、逻辑操作符、元素操作符、数组操作符、文本搜索操作符等几种类型。 以下是这些操作…...

【Linux】探索Linux进程状态 | 僵尸进程 | 孤儿进程

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 目录 一、进程状态1.1运行状态1.2阻塞状态1.3挂起状态 二、具体L…...

大数据股票简单分析

目录标题 内容说明解题量化金融的含义量化交易策略 点击直接资料领取 内容 1解释量化金融的含义&#xff0c;调研并给出至少 5种量化交易的策略或方法 2.完成Tushare Pro 的安装、注册&#xff0c;获取自己的 Token&#xff0c;查阅网站内的接口讲解和示例; 3通过Python 编程完…...

从零开始搭建链上dex自动化价差套利程序(11)

风险控制 需要将仓位杠杆控制到3倍以内&#xff0c;由于dydx与apex没有获取仓位杠杆的接口&#xff0c;但是每次发送交易的数额可以决定&#xff0c;故而可以设置每次发送总仓位1.5倍杠杆的数额&#xff0c;然后设置一个变量保证每个方向上的交易不超过2次&#xff0c;即可保证…...

2023.12面试题汇总小结

文章目录 Java字节码都包括哪些内容Java双亲委派机制如何打破Java Memory Model是什么synchronized的锁优化是什么CountDownLatch、CyclicBarrier、Semaphore有啥区别&#xff0c;什么场景下使用MySQL MVCC原理MySQL RR隔离级别&#xff0c;会出现幻读吗MySQL的RR隔离级别下&am…...

Linux权限命令详解

Linux权限命令详解 文章目录 Linux权限命令详解一、什么是权限&#xff1f;二、权限的本质三、Linux中的用户四、linux中文件的权限4.1 文件访问者的分类&#xff08;人&#xff09;4.2 文件类型和访问权限&#xff08;事物属性&#xff09; 五、快速掌握修改权限的做法【第一种…...

【Android】Glide的简单使用(下)

文章目录 缓存设置内存缓存硬盘缓存自定义磁盘缓存行为图片请求优先级缩略图旋转图片Glide的回调:TargetsBaseTargetTarget注意事项设置具体尺寸的Target 调试及Debug获取异常信息 配置第三方网络库自定义缓存 缓存设置 GlideApp .with(context).load(gifUrl).asGif().error(…...

TCP对数据的拆分

应用程序的数据一般都比较大&#xff0c;因此TCP会按照网络包的大小对数据进行拆分。 当发送缓冲区中的数据超过MSS的长度&#xff0c;数据会被以MSS长度为单位进行拆分&#xff0c;拆分出来的数据块被放进单独的网路包中。 根据发送缓冲区中的数据拆分情况&#xff0c;当判断…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

C# winform教程(二)----checkbox

一、作用 提供一个用户选择或者不选的状态&#xff0c;这是一个可以多选的控件。 二、属性 其实功能大差不差&#xff0c;除了特殊的几个外&#xff0c;与button基本相同&#xff0c;所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...

2025.6.9总结(利与弊)

凡事都有两面性。在大厂上班也不例外。今天找开发定位问题&#xff0c;从一个接口人不断溯源到另一个 接口人。有时候&#xff0c;不知道是谁的责任填。将工作内容分的很细&#xff0c;每个人负责其中的一小块。我清楚的意识到&#xff0c;自己就是个可以随时替换的螺丝钉&…...