处理GTK和x2B的替代方法;锈蚀事件

处理GTK和x2B的替代方法;锈蚀事件,gtk,rust,Gtk,Rust,目前,我使用Rc和RefCell管理GTK+事件,如下例所示: extern crate gtk; use std::cell::RefCell; use std::rc::Rc; use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, Window, WindowType}; use gtk::Orientation::Vertical; struct Model { count: i32, }

目前,我使用
Rc
RefCell
管理GTK+事件,如下例所示:

extern crate gtk;

use std::cell::RefCell;
use std::rc::Rc;

use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, Window, WindowType};
use gtk::Orientation::Vertical;

struct Model {
    count: i32,
}

fn main() {
    gtk::init().unwrap();

    let window = Window::new(WindowType::Toplevel);

    let model = Rc::new(RefCell::new(Model { count: 0 }));

    let vbox = gtk::Box::new(Vertical, 0);
    window.add(&vbox);

    let label = Label::new(Some("0"));
    vbox.add(&label);

    let button = Button::new_with_label("Increment");
    vbox.add(&button);
    window.show_all();

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    {
        let model = model.clone();
        button.connect_clicked(move |_| {
            {
                (*model.borrow_mut()).count += 1;
            }
            label.set_text(&format!("{}", (*model.borrow()).count));
        });
    }

    gtk::main();
}
我对这段代码的主要问题是由于
RefCell
s而需要的样板文件

另外,我觉得这是一种糟糕的做法,可能会导致恐慌(这不是我的主要问题,所以不要建议使用
互斥锁,因为在某些示例中,这可能会导致死锁)

所以我认为我可以用类似于Elm的方式处理事件:一个函数接收信号,模型可以在其中更新。 然而,我无法在Rust中实现这一点。 以下是一个尝试:

extern crate gtk;

use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, WindowType};
use gtk::Orientation::Vertical;

use Message::Increment;

enum Message {
    Increment,
}

struct Window {
    label: Label,
    model: Model,
    queue: Rc<RefCell<VecDeque<Message>>>,
    view: gtk::Window,
}

impl Window {
    fn new() -> Self {
        let window = gtk::Window::new(WindowType::Toplevel);

        let vbox = gtk::Box::new(Vertical, 0);
        window.add(&vbox);

        let label = Label::new(Some("0"));
        vbox.add(&label);

        let button = Button::new_with_label("Increment");
        vbox.add(&button);
        window.show_all();

        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });

        let queue = Rc::new(RefCell::new(VecDeque::new()));

        {
            let queue = queue.clone();
            button.connect_clicked(move |_| {
                (*queue.borrow_mut()).push_back(Increment);
            });
        }

        Window {
            label: label,
            queue: queue,
            model: Model { count: 0 },
            view: window,
        }
    }

    // How to call this method when a message is received?
    fn update(&mut self, message: Message) {
        match message {
            Increment => {
                self.model.count += 1;
                self.label.set_text(&format!("{}", self.model.count));
            },
        }
    }
}

struct Model {
    count: i32,
}

fn main() {
    gtk::init().unwrap();

    let window = Window::new();

    gtk::main();
}
外部板条箱gtk;
使用std::cell::RefCell;
使用std::collections::VecDeque;
使用std::rc::rc;
使用gtk:{Button,ButtonExt,ContainerText,Inhibit,Label,WidgetExt,WindowType};
使用gtk::Orientation::Vertical;
使用Message::Increment;
枚举消息{
增量,
}
结构窗口{
标签:标签,
模型:模型,
队列:Rc,,
视图:gtk::窗口,
}
impl窗口{
fn new()->Self{
让window=gtk::window::new(WindowType::Toplevel);
设vbox=gtk::Box::new(垂直,0);
添加(&vbox);
让label=label::new(一些(“0”);
vbox.add(&label);
let button=按钮::带有标签的新按钮(“增量”);
vbox.add(&按钮);
window.show_all();
window.connect_delete_事件(| |,|{
gtk::main_quit();
禁止(错误)
});
让queue=Rc::new(RefCell::new(VecDeque::new());
{
让queue=queue.clone();
按钮。单击连接(移动){
(*queue.borrow_mut()).push_back(增量);
});
}
窗口{
标签:标签,
队列:队列,
模型:模型{计数:0},
视图:窗口,
}
}
//收到消息时如何调用此方法?
fn更新(&mut self,消息:消息){
匹配消息{
增量=>{
self.model.count+=1;
self.label.set_text(&format!(“{}”,self.model.count));
},
}
}
}
结构模型{
计数:i32,
}
fn main(){
gtk::init().unwrap();
让窗口=窗口::新建();
gtk::main();
}
当消息
队列
更新时,如何调用
update()
方法

这是一个可行的方法吗

如果没有,您是否知道有什么替代方案可以解决此问题

也许可以使用基于
未来
板条箱的解决方案?
在这种情况下,我如何管理两个主回路(gtk+1和
tokio
1)


还是使用频道的解决方案?

我找到了这个问题的解决方案

以下是我通过我的例子所取得的成果:

extern crate gtk;

use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, WindowType};
use gtk::Orientation::Vertical;

use Message::Increment;

macro_rules! connect {
    ($source:ident :: $event:ident, $target:ident :: $message:expr) => {
        let target = &mut *$target as *mut _;
        $source.$event(move |_| {
            let target: &mut Window = unsafe { &mut *target };
            target.update($message);
        });
    };
}

enum Message {
    Increment,
}

struct Window {
    label: Label,
    model: Model,
    view: gtk::Window,
}

impl Window {
    fn new() -> Box<Self> {
        let window = gtk::Window::new(WindowType::Toplevel);

        let vbox = gtk::Box::new(Vertical, 0);
        window.add(&vbox);

        let label = Label::new(Some("0"));
        vbox.add(&label);

        let button = Button::new_with_label("Increment");
        vbox.add(&button);
        window.show_all();

        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });

        let mut window = Box::new(Window {
            label: label,
            model: Model { count: 0 },
            view: window,
        });

        connect!(button::connect_clicked, window::Increment);

        window
    }

    fn update(&mut self, message: Message) {
        match message {
            Increment => {
                self.model.count += 1;
                self.label.set_text(&format!("{}", self.model.count));
            },
        }
    }
}

struct Model {
    count: i32,
}

fn main() {
    gtk::init().unwrap();

    let _window = Window::new();

    gtk::main();
}

我找到了解决这个问题的办法

以下是我通过我的例子所取得的成果:

extern crate gtk;

use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, WindowType};
use gtk::Orientation::Vertical;

use Message::Increment;

macro_rules! connect {
    ($source:ident :: $event:ident, $target:ident :: $message:expr) => {
        let target = &mut *$target as *mut _;
        $source.$event(move |_| {
            let target: &mut Window = unsafe { &mut *target };
            target.update($message);
        });
    };
}

enum Message {
    Increment,
}

struct Window {
    label: Label,
    model: Model,
    view: gtk::Window,
}

impl Window {
    fn new() -> Box<Self> {
        let window = gtk::Window::new(WindowType::Toplevel);

        let vbox = gtk::Box::new(Vertical, 0);
        window.add(&vbox);

        let label = Label::new(Some("0"));
        vbox.add(&label);

        let button = Button::new_with_label("Increment");
        vbox.add(&button);
        window.show_all();

        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });

        let mut window = Box::new(Window {
            label: label,
            model: Model { count: 0 },
            view: window,
        });

        connect!(button::connect_clicked, window::Increment);

        window
    }

    fn update(&mut self, message: Message) {
        match message {
            Increment => {
                self.model.count += 1;
                self.label.set_text(&format!("{}", self.model.count));
            },
        }
    }
}

struct Model {
    count: i32,
}

fn main() {
    gtk::init().unwrap();

    let _window = Window::new();

    gtk::main();
}

互斥锁死锁是因为GTK+信号与运行在同一线程上的
GTK::main()
信号在同一线程上运行。我不知道一个好的特定于锈蚀的解决方案,但我可以给出一个特定于GTK+的解决方案:使用空闲回调将内容从另一个线程发送到GTK+线程。我知道关于
idle\u add()
,但我不知道如何从它调用
update()
方法,因为对象需要是静态的(或者在
Rc
中,这是我试图避免的)。互斥锁死锁是因为GTK+信号与
GTK::main()运行在同一个线程上
继续运行。我不知道一个好的特定于锈蚀的解决方案,但我可以给出一个特定于GTK+的解决方案:使用空闲回调将内容从另一个线程发送到GTK+线程。我知道关于
空闲添加()
,但我不知道如何从它调用
更新()
方法,因为对象需要是静态的(或者在
Rc
中,这正是我试图避免的)。