3个不稳定版本
0.4.1 | 2020年12月12日 |
---|---|
0.4.0 | 2020年11月22日 |
0.3.0 | 2020年1月25日 |
在GUI中排名#369
每月下载量34次
在flowide中使用
21KB
153 行
gtk-rs-state
在稳定版上运行。
这不是最快的实现,但对于几乎所有用例来说应该足够了。
Cargo.toml
[dependencies]
gtk-rs-state = "0.3"
示例用法
使用这个库归结为
- 调用gtk_refs!宏。
- 在启动事件循环之前调用init_storage()。
- 在其他线程中调用do_in_gtk_eventloop()来修改小部件。
不要在主线程中调用do_in_gtk_eventloop(),因为这会阻塞。
gtk_refs!(
pub mod widgets; // The macro emits a new module with this name
struct WidgetRefs; // The macro emits a struct with this name containing:
main_window : gtk::Window , // widget_name : Widgettype
button1 : gtk::Button // ..
);
fn main() {
if gtk::init().is_err() {
println!("Failed to initialize GTK.");
return;
}
let window = Window::new(WindowType::Toplevel);
window.set_title("gtk-rs-state Example Program");
window.set_default_size(350, 70);
let button = Button::new_with_label("Spawn another thread!");
window.add(&button);
window.show_all();
window.connect_delete_event(|_, _| {
gtk::main_quit();
Inhibit(false)
});
button.connect_clicked(|_| {
std::thread::spawn(some_workfunction);
println!("Clicked!");
});
// You need the following two statements to prepare the
// static storage needed for cross thread access.
// See the `from_glade.rs` example for a more elegant solution
let widget_references = widgets::WidgetRefs {
main_window: window.clone(),
button1: button.clone(),
};
widgets::init_storage(widget_references);
// End
// This type has a function for each of your widgets.
// These functions return a clone() of the widget.
window.show_all();
window.connect_delete_event(move |_, _| {
gtk::main_quit();
Inhibit(false)
});
// Start event loop
gtk::main();
}
fn compute() {
use std::thread::sleep;
use std::time::Duration;
sleep(Duration::from_secs(1));
}
fn some_workfunction() {
let mut i = 0;
loop {
compute();
i += 1;
let text = format!("Round {} in {:?}", i, std::thread::current().id());
widgets::do_in_gtk_eventloop(|refs| {
refs.button1().set_label(&text);
});
}
}
该宏生成以下代码
pub mod widgets {
pub struct WidgetRefs {
pub main_window : gtk::Window,
...
}
impl From<>k::Builder> for WidgetRefs { ... };
impl WidgetRefs {
fn main_window() -> gtk::Window { } // returns a .clone() of the widget
...
}
pub fn init_storage(WidgetRefs);
pub fn init_storage_from_builder(>k::Builder);
pub fn do_in_gtk_eventloop( FnOnce(Rc<WidgetRefs>) );
}
它是如何工作的?
- 您提供的闭包通过
glib::idle_add()
在GTK事件循环中执行。 - 在调用点
do_in_gtk_eventloop()
会等待闭包运行。 - 来自多个线程的闭包将始终顺序执行。
- 如果闭包崩溃,
do_in_gtk_eventloop()
也会崩溃。您可能看不到崩溃,因为进程通常退出得太快。
如果您想: - 在结构体中使用额外的非发送字段(除了小部件引用以外的其他内容) - 使用glade,请参阅示例文件夹
实现是如何工作的?
+---------------------------------+ +----------------------------------+
|GTK event loop thread | |Global statics |
| | | |
| +----------------------------+ | | TX : Sender<(Fn, Cb)> |
| |Thread local statics | | | |
| | | | | |
| | DATA : Non-Send Refereces | | +----------------------------------+
| | RX : Receiver<(Fn, Cb)> | |
| | | | +----------------------------------+
| +----------------------------+ | |Some other thread |
| | | |
| | | do some stuff |
| +---------------------------+ | | |
| |event loop() | | | call do_in_gtk_eventloop(Fn) |
| | | | | This Fn has access to DATA |
| | +----------------------+ | | | |
| | |closure added with | | | | |
| | |idle_add() to execute | | | +----------------------------------+
| | |on the gtk thread { | | |
| | | <-----------------------------------------------+
| | | Pop (Fn,Cb) from RX | | | |
| | | Call Fn(DATA) | | | |
| | | Signal end of Fn | | | +----------------------------------+ |
| | | via Cb | | | |do_in_gtk_eventloop(Fn) | |
| | | | | | | | |
| | | | | | | Box closure Fn and transmute | |
| | +----------------------+ | | | livetime to 'static | |
| | | | | | |
| +---------------------------+ | | Create a signal Cb | |
| | | Push (boxed Fn, Cb) to TX | |
+---------------------------------+ | Add this closure via idle_add() +---+
| Wait for the signal Cb |
| return |
| |
| |
+----------------------------------+
init_storage()
初始化DATA,RX和TX。
使用unsafe
有一个使用unsafe,只是为了方便。它允许闭包引用局部堆栈,而不是要求闭包上的'static。
您可以轻松删除unsafe,但之后您被迫将所有内容移动到with_ref
闭包中。
依赖项
~17MB
~401K SLoC