其他 GUI 框架
核心 crate 里没有 gpui。接入任何框架都只需回答一个问题:我怎么把一个闭包投递到主线程? 把这件事注册一次,本指南其余内容便原封不动地适用。
rust
// Cx is whatever your toolkit hands out on the main thread; it need not be Send.
let (bridge, app) = GuiBridge::builder(move |task: Box<dyn FnOnce(&mut MyCx) + Send>| {
my_toolkit::post_to_main_thread(move || {
let cx = /* obtain &mut MyCx here */;
task(cx);
});
})
.build();| 框架 | 投递方式 |
|---|---|
| gpui | channel + 一个调用 cx.update 的 cx.spawn 排空循环——已封装为 purview-gpui |
| Slint | slint::invoke_from_event_loop;在闭包内通过 weak handle 触达控件 |
| GTK | glib::idle_add |
| egui | 入队,在重绘时排空 |
Send 的巧妙之处
Cx 只被携带在投递闭包的装箱类型内部,因此即使 Cx 本身不是 Send,GuiBridge<Cx> 以及所有句柄依然是 Send + Sync。正是这一点让服务端能跑在后台线程上,而你的上下文从不离开主线程。
自己回到主线程
在 on_ui 处理器之外——比如在 async 处理器里,或任何后台任务中——显式跳回主线程:
rust
let ui = app.ui(); // Ui<Cx>, cheap to clone, Send + Sync
let value = ui.run(|cx| read_widget(cx)).await;Ui::run 会投递你的闭包并等待它的返回值。如果主循环已经退出,它会 panic——这是诚实的结果:已经没有上下文可供运行了。