如何在使用gpui的 Rust GUI应用中添加系统托盘图标?
我正在尝试用gpui编写一个Rust GUI应用。
如何将托盘图标添加到代码?
Cargo.toml:
[dependencies]
gpui = "0.2.2"
gpui-component = "0.5.1"
tray-icon = "0.24.0"
image = "0.25.10"
main.rs:
重写 main.rs,在用户状态 HelloWorld 中添加tray: Option
use gpui::{div, prelude::*, px, rgb, size, App, Application, Bounds, Context, SharedString, Window,
WindowBounds, WindowOptions, actions, KeyBinding, WindowKind};
use gpui_component::{TitleBar, Root, };
use gpui_component::button::{Button, };
use tray_icon::{TrayIconBuilder, TrayIcon,
TrayIconEvent,
menu::{ Menu, MenuItem, MenuEvent, MenuEventReceiver }};
actions!(HelloWorld, [Quit]);
// 定义我们的 "Hello, World!" 视图结构体
// 这个结构体将持有视图的状态
struct HelloWorld {
text: SharedString,
// hold tray-icon
tray: Option<TrayIcon>,
}
impl HelloWorld {
fn load_icon(path: &std::path::Path) -> tray_icon::Icon {
let (icon_rgba, icon_width, icon_height) = {
let image = image::open(path)
.expect("Failed to open icon path")
.into_rgba8();
let (width, height) = image.dimensions();
let rgba = image.into_raw();
(rgba, width, height)
};
tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
}
fn init_tray() -> TrayIcon {
let icon = HelloWorld::load_icon(std::path::Path::new("/Users/...../images/icon.png"));
let tray_menu = HelloWorld::new_tray_menu();
TrayIconBuilder::new()
.with_menu(Box::new(tray_menu))
.with_tooltip("system-tray - tray icon library!")
.with_icon(icon)
.build()
.unwrap()
}
fn new_tray_menu() -> Menu {
let menu = Menu::new();
let item1 = MenuItem::new("item1", true, None);
if let Err(err) = menu.append(&item1) {
println!("{err:?}");
}
menu
}
fn init_events() {
if let Ok(event) = TrayIconEvent::receiver().try_recv() {
println!("{:?}", event); // not fired
}
TrayIconEvent::set_event_handler(Some(move |event| {
// here ,
}));
if let Ok(event) = TrayIconEvent::receiver().try_recv() {
println!("tray event: {:?}", event); // not fired
}
if let Ok(event) = MenuEvent::receiver().try_recv() {
println!("menu event: {:?}", event); // not fired
}
}
}
// 为 HelloWorld 实现 Render trait,这是 GPUI 渲染系统要求的
impl Render for HelloWorld {
// 渲染方法:这是 GPUI 的核心
// 它描述了视图在任何时候应该是什么样子
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
// .flex() 使其成为一个 Flexbox 容器
.flex()
// 改为垂直方向排列
.flex_col()
// 添加元素间距
.gap_3()
// .bg() 设置背景色,rgb() 是一个颜色辅助函数
.bg(rgb(0x505050))
.size(px(500.0))
// .items_center() 和 .justify_center() 实现垂直和水平居中
.justify_center()
.items_center()
.shadow_lg()
.border_1()
.border_color(rgb(0x0000ff))
.text_xl()
.child(format!("Hello, {}!\r\n按 cmd + q 退出程序。", &self.text))
.child(
div()
.flex()
.gap_2()
.child(div().size_8().bg(gpui::red()))
.child(div().size_8().bg(gpui::green()))
.child(div().size_8().bg(gpui::blue()))
.child(div().size_8().bg(gpui::yellow()))
.child(div().size_8().bg(gpui::black()))
.child(div().size_8().bg(gpui::white())),
)
.child(
Button::new("ok").label("我是一个按钮")
.on_click(|_evt, _window, _app| {
println!("我被按下了")
})
)
}
}
fn gpui_build() {
Application::new().run(|cx: &mut App| {
HelloWorld::init_events();
//若要使用 gpui_component 下的控件,需要下面这句话
gpui_component::init(cx);
//绑定快捷键 cmd + q, 行为 Quit
cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]);
// 设置窗口初始位置和大小
let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx);
let _ = cx.open_window(
WindowOptions {
kind: WindowKind::Floating,
window_bounds: Some(WindowBounds::Windowed(bounds)),
titlebar: Some(TitleBar::title_bar_options()),
window_min_size: Some(gpui::Size {
width: px(480.0),
height: px(480.0),
}),
// kind: WindowKind::PopUp,
..Default::default()
},
// mac 系统下, 在关闭了主窗口后,退出应用程序 的作法
|window, cx| {
// 绑定 Quit 行为
cx.on_action(|_: &Quit, _cx| {
println!("Quit shortcut triggered");
std::process::exit(0);
});
//绑定窗口的关闭按钮的点击事件
window.on_window_should_close(cx, |_window, _cx| {
println!("打印>> Main window is closing. Exiting app.");
std::process::exit(0);
});
let view = cx.new(|cx| {
HelloWorld {
text: "world".into(),
tray: Some(HelloWorld::init_tray())
}
});
cx.new(|cx| Root::new(view, window, cx))
},
);
//将窗口提到前台
cx.activate(true);
});
}
fn main() {
gpui_build();
}
构建并运行时,托盘会显示出来,单击托盘后,会弹出包含项“item1”的菜单;点击该菜单项时,却没有触发任何菜单点击事件。请帮忙,如何监听菜单点击事件?
解决方案
你需要扩展状态结构,用以存储在创建托盘图标时返回的对象,使用 tray-icon
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。