我正在尝试实现一个容器,其中包含GUI小部件列表,其中每个小部件都需要访问该容器。每个小部件可能需要在某些事件上修改其他小部件。例如,当用户单击按钮时,编辑器文本将更新。
我可以使用盒装use std::collections::HashMap;
struct SharedItem<'a> {
pub value: String,
pub store: &'a HashMap<String, SharedItem<'a>>,
}
fn trigger_button(button: &SharedItem) {
// use case where SharedItem has to be mutable
let mut editor = button.store.get(&"editor".to_string()).unwrap();
editor.value = "value inserted by button".to_string();
}
fn main() {
// map shared items by their name
let mut shared_store: HashMap<String, SharedItem> = HashMap::new();
// create components
let editor = SharedItem {
value: "editable content".to_string(),
store: &shared_store,
};
let button = SharedItem {
value: "button".to_string(),
store: &shared_store,
};
shared_store.insert("button".to_string(), button);
shared_store.insert("editor".to_string(), editor);
// now update the editor by triggering button
trigger_button(shared_store.get(&"button".to_string()).unwrap());
}
,但它无法解决问题。什么是实现我需要的最简单方法?
这是我目前所拥有的,它没有编译,但你会得到这个想法:
{{1}}
答案 0 :(得分:3)
这是必需的,因为小部件可能需要在某些事件上修改其他小部件。例如:用户单击按钮,结果编辑器文本将更新。
正因为这就是大多数GUI在OO语言中的运作方式并不意味着必须这样做。
在这种特定情况下,一个简单的解决方案是:
因此,在任何时间点,系统中最多存在一个小部件上的一个可变句柄,这样可以避免别名并使Rust保持高兴。
注意:这个答案假定您不需要编辑器小部件的同步响应,如果您使用这样的系统,则会陷入回调地狱。
答案 1 :(得分:3)
如何拥有物品可以访问容器的容器?
你cannot do this with references。您可以使用reference-counted boxed values执行此操作。
但是,你仍然可以通过不同的方式思考来解决问题...
每个小部件都需要访问该容器。每个小部件可能需要修改某些事件上的其他小部件
如果它适合您的问题域,只需在单向数据流中发布事件就更清晰了:
// Create meaningful events with data pertinent to those events.
enum Event {
UpdateText,
Click,
}
struct Events(Vec<Event>);
impl Events {
fn push(&mut self, event: Event) { self.0.push(event) }
}
trait Widget {
fn event_happened(&mut self, event: &Event, triggered_events: &mut Events);
fn draw(&self);
}
struct Widgets(Vec<Box<Widget>>);
struct TextField(String);
impl Widget for TextField {
fn event_happened(&mut self, event: &Event, _: &mut Events) {
match *event {
Event::UpdateText => self.0.push_str("event"),
_ => (),
}
}
fn draw(&self) {
println!("Drawing text: {}", self.0);
}
}
struct Button;
impl Widget for Button {
fn event_happened(&mut self, event: &Event, triggered_events: &mut Events) {
match *event {
Event::Click => triggered_events.push(Event::UpdateText),
_ => (),
}
}
fn draw(&self) {
println!("Drawing button");
}
}
fn main() {
let mut events = Events(vec![]);
let mut widgets = Widgets(vec![
Box::new(TextField(String::new())),
Box::new(Button),
]);
// This would probably loop forever until a shutdown event was posted
for i in 0..10 {
for widget in &widgets.0 {
widget.draw();
}
// Fake a click at some point
if i == 0 {
events.push(Event::Click);
}
let mut next_events = Events(vec![]);
for event in &events.0 {
for widget in &mut widgets.0 {
widget.event_happened(event, &mut next_events);
}
}
events = next_events;
}
}
要清楚,这是Matthieu M.建议的内容(没有目标ID);我刚刚输入了这个例子,所以我想发布它^ _ ^。