Tauri框架实战——鼠标左键单击托盘图标不显示菜单

背景

近期,我基于自研的个人时间管理 Web 应用 「时光助手」,借助 AI 辅助开发,通过 Tauri 框架完成了 Windows 客户端的打包工作。初次体验 Tauri 便收获了不错的反馈 ------ 其生成的客户端体积轻量化、运行性能优异,且与 Web 端的适配性远超预期。

不过,从 Web 应用到桌面客户端的迁移,并非简单的 "打包封装" 就能一蹴而就,目前仍有不少细节有待打磨。后续我计划从两个维度深耕:一是系统性吃透 Tauri 框架的底层逻辑与进阶用法;二是对 AI 生成的代码进行全面人工复核。毕竟 AI 生成的代码存在两个明显痛点:部分逻辑的实现原理模糊不清,可能暗藏隐患或冗余;再加上各类功能框架与组件版本差异显著、官方文档覆盖不全,AI 受限于底层机制产生的 "幻觉" 问题会被进一步放大。唯有人工逐行校验,才能让代码真正稳定可靠。

鼠标左键点击托盘图标,不弹出菜单

应用最小化到托盘后,用户如想显示主窗口或退出,通过右键托盘图标,弹出菜单实现的,当前的问题在于,用户点击鼠标左键,也会弹出菜单,需要屏蔽掉左键菜单。

依然使用 TRAE,将需求告知 ,如下:

rust 复制代码
tauri框架生成的客户端,当最小化托盘图标时,鼠标左键单击不要显示菜单,而是显示主窗口

AI 处理完后,发现代码没变化,细看发现 AI 居然跳出了原先的项目结构,新建了一个目录和文件,比较无语,如下:

rust 复制代码
/e/dev/meet/platform-web/src-tauri/src/lib.rs

明确告诉它搞错了,正确的位置是E:\dev\meet\platform-web\src-tauri\src,才对项目内应该修改的源码进行调整,看代码逻辑,监控了托盘图标的点击事件,如果判断是鼠标左键单击,则显示主窗口,代码如下:

rust 复制代码
// 修改托盘图标配置部分,完整替换以下代码:

// 5. 创建系统托盘
let _tray = TrayIconBuilder::new()
    .icon(app.default_window_icon().unwrap().clone())
    .tooltip("时光助手")
    .menu(&tray_menu)
    // 处理托盘图标点击事件 - 左键单击显示主窗口
    .on_tray_icon_event(|tray, event| {
        match event {
            TrayIconEvent::Click { button, .. } => {
                // 只处理左键单击
                if button == tauri::MouseButton::Left {
                    let app_handle = tray.app_handle();
                    // 获取窗口并显示
                    if let Some(window) = app_handle.get_webview_window("main") {
                        let _ = window.show();
                        let _ = window.set_focus();
                    }
                }
            }
            TrayIconEvent::DoubleClick { .. } => {
                let app_handle = tray.app_handle();
                // 获取窗口并显示
                if let Some(window) = app_handle.get_webview_window("main") {
                    let _ = window.show();
                    let _ = window.set_focus();
                }
            }
            _ => {}
        }
    })
    // 处理菜单点击事件
    .on_menu_event(|tray, event| {
        let app_handle = tray.app_handle();
        match event.id().as_ref() {
            "show_window" => {
                if let Some(window) = app_handle.get_webview_window("main") {
                    let _ = window.show();
                    let _ = window.set_focus();
                }
            }
            "quit_app" => {
                // 退出应用
                app_handle.exit(0);
            }
            _ => {}
        }
    })
    .build(app)?;

结果,打包的时候提示编译错误......

rust 复制代码
   Compiling tauri-plugin v2.5.2
   Compiling tauri-codegen v2.5.2
    Info File src-tauri\src\lib.rs changed. Rebuilding application...
   Compiling tauri-utils v2.8.1
   Compiling windows v0.61.3
   Compiling tauri-build v2.5.3
   Compiling tauri-plugin v2.5.2
   Compiling tauri-codegen v2.5.2
   Compiling tauri v2.9.5
   Compiling tauri-macros v2.5.2
   Compiling tauri-plugin-os v2.3.2
   Compiling tauri-plugin-notification v2.3.3
   Compiling TimeHelper v3.4.0 (E:\dev\meet\platform-web\src-tauri)
   Compiling webview2-com-sys v0.38.0
   Compiling tao v0.34.5
   Compiling tauri-winrt-notification v0.7.2
   Compiling notify-rust v4.11.7
   Compiling webview2-com v0.38.0
    Info File src-tauri\tauri.conf.json changed. Rebuilding application...
   Compiling windows v0.61.3
   Compiling TimeHelper v3.4.0 (E:\dev\meet\platform-web\src-tauri)
   Compiling webview2-com-sys v0.38.0
   Compiling tao v0.34.5
   Compiling tauri-winrt-notification v0.7.2
   Compiling notify-rust v4.11.7
   Compiling webview2-com v0.38.0
   Compiling tauri-runtime v2.9.2
   Compiling wry v0.53.5
   Compiling tauri-runtime-wry v2.9.3
   Compiling tauri v2.9.5
   Compiling tauri-plugin-single-instance v2.3.6
   Compiling tauri-plugin-notification v2.3.3
   Compiling tauri-plugin-os v2.3.2
error[E0433]: failed to resolve: could not find `MouseButton` in `tauri`
  --> src\lib.rs:66:49
   |
66 | ...                   if button == tauri::MouseButton::Left {
   |                                           ^^^^^^^^^^^ could not find `MouseButton` in `tauri`
   |
help: consider importing this enum
   |
 2 + use tauri::tray::MouseButton;
   |
help: if you import `MouseButton`, refer to it directly
   |
66 -                             if button == tauri::MouseButton::Left {
66 +                             if button == MouseButton::Left {
   |

For more information about this error, try `rustc --explain E0433`.​

把错误扔给 AI,AI 分析是包搞错了,如下:

rust 复制代码
我看到编译过程中出现了错误,问题是找不到 MouseButton 类型。根据错误提示,MouseButton 应该来自 tauri::tray 模块,而不是直接在 tauri 根模块下。

然后导入了 tray 下的 MouseButton,结果代码使用还是 tauri 包下,又搞了一轮编译不通过,最终提供了一版编译无问题,代码如下:

rust 复制代码
// 使用 Tauri 2.0 正确 API 实现所有功能
use tauri::{
    menu::{MenuBuilder, MenuItemBuilder},
    tray::{MouseButton, TrayIconBuilder, TrayIconEvent},
    Manager,
};
use tauri_plugin_single_instance::init as single_instance_init;

pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_os::init())
        .plugin(tauri_plugin_notification::init())
        .setup(|app| {
            // 1. 初始化单实例插件
            app.handle()
                .plugin(single_instance_init(|app, _argv, _cwd| {
                    // 当新实例启动时,激活现有实例的窗口
                    if let Some(window) = app.get_webview_window("main") {
                        let _ = window.show();
                        let _ = window.set_focus();
                    }
                }))?;

            // 2. 获取主窗口
            let main_window = match app.get_webview_window("main") {
                Some(window) => window,
                None => {
                    eprintln!("主窗口(ID: main)未创建!");
                    return Ok(());
                }
            };

            // 3. 监听窗口关闭事件
            let window_clone = main_window.clone();
            main_window.on_window_event(move |event| {
                if let tauri::WindowEvent::CloseRequested { api, .. } = event {
                    // 阻止默认关闭
                    api.prevent_close();
                    // 隐藏窗口
                    let _ = window_clone.hide();
                }
            });

            // 4. 创建托盘菜单
            let show_window_item = MenuItemBuilder::new("显示主窗口")
                .id("show_window")
                .build(app)?;

            let quit_app_item = MenuItemBuilder::new("退出应用").id("quit_app").build(app)?;

            let tray_menu = MenuBuilder::new(app)
                .item(&show_window_item)
                .item(&quit_app_item)
                .build()?;

            // 5. 创建系统托盘
            let _tray = TrayIconBuilder::new()
                .icon(app.default_window_icon().unwrap().clone())
                .tooltip("时光助手")
                .menu(&tray_menu)
                // 处理托盘点击事件 - 修改这里!
                .on_tray_icon_event(|tray, event| {
                    match event {
                        // 添加左键单击事件处理
                        TrayIconEvent::Click { button, .. } => {
                            if button == MouseButton::Left {
                                let app_handle = tray.app_handle();
                                // 获取窗口并显示
                                if let Some(window) = app_handle.get_webview_window("main") {
                                    let _ = window.show();
                                    let _ = window.set_focus();
                                }
                            }
                        }
                        // 保持双击事件处理不变
                        TrayIconEvent::DoubleClick { .. } => {
                            let app_handle = tray.app_handle();
                            // 获取窗口并显示
                            if let Some(window) = app_handle.get_webview_window("main") {
                                let _ = window.show();
                                let _ = window.set_focus();
                            }
                        }
                        _ => {}
                    }
                })
                // 处理菜单点击事件
                .on_menu_event(|tray, event| {
                    let app_handle = tray.app_handle();
                    match event.id().as_ref() {
                        "show_window" => {
                            if let Some(window) = app_handle.get_webview_window("main") {
                                let _ = window.show();
                                let _ = window.set_focus();
                            }
                        }
                        "quit_app" => {
                            // 退出应用
                            app_handle.exit(0);
                        }
                        _ => {}
                    }
                })
                .build(app)?;

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("运行 Tauri 应用失败");
}

但是,经测试,发现还是有问题,左键点击依然会弹出菜单,快速闪烁一下后消失......

代码逻辑看上去一切正常,于是只能开启人工诊断模式。

去官网查看托盘功能相关文档:https://tauri.app/zh-cn/learn/system-tray/#创建托盘图标

发现官方有明确说明,默认情况下,确实单击左键会显示菜单,如下图:

按照官方说明,构建托盘的时候,设置一个属性menu_on_left_click就可以了。

手工修改,打包时提示警告,方法已过时......

rust 复制代码
warning: use of deprecated method `tauri::tray::TrayIconBuilder::<R>::menu_on_left_click`: Use `TrayIconBuilder::show_menu_on_left_click` instead.
  --> src\lib.rs:61:18
   |
61 |                 .menu_on_left_click(false)
   |                  ^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(deprecated)]` on by default

功能测试倒是正常了,终于左键不再弹出菜单了。

根据警告的提示,将属性从已废弃的menu_on_left_click,调整为show_menu_on_left_click,编译也不再报警告了,测试功能也正常。

小结

看起来一个挺简单的小问题,AI 折腾了半小时,出现了多次错误,最终也没实现预期效果。人工查阅官方文档,10 分钟就完成了处理,当然也存在一定的运气成分,刚好这个问题,官方文档里有明确说明,从警告信息来看,官方文档也陈旧了......在这种局面下,AI 也难以给出准确的答案。

相关推荐
liliangcsdn2 小时前
LLM训练中batchsize与过拟合和泛化的关系
人工智能·算法·机器学习
ccLianLian2 小时前
Segment Anything Model
人工智能·深度学习·计算机视觉
week_泽2 小时前
第10课:从零构建生产级AI Agent服务技术方案 - 学习笔记_10
人工智能·笔记·学习·ai agent
lynnlovemin2 小时前
AI时代信息安全:从挑战突围到智能防御体系构建
人工智能·信息安全
西柚小萌新2 小时前
【计算机视觉CV:标注工具】--labelimg+labelme
人工智能·计算机视觉
躺平的赶海人2 小时前
PyTorch 安装指南:快速开启深度学习之旅
人工智能·pytorch·深度学习
IT_陈寒2 小时前
Vue3性能优化实战:5个被低估的API让我减少了40%的代码量
前端·人工智能·后端
Hcoco_me2 小时前
大模型面试题64:介绍下PPO的训练流程
人工智能·深度学习·机器学习·chatgpt·机器人
高洁012 小时前
AI智能体搭建(2)
人工智能·深度学习·算法·机器学习·知识图谱