简体   繁体   English

使用rust-gnome时如何将自己的数据传入GTK回调?

[英]How can I get my own data to a GTK callback when using rust-gnome?

... or, How can I subclass a gtk::Widget? ...或者,我如何子类化gtk :: Widget?

I have the following dependencies in my Cargo.toml : 我的Cargo.toml有以下依赖Cargo.toml

[dependencies]
num = "*"
gtk = "*"
cairo-rs = "*"
gdk = "*"
time = "*"

I want to create my own type of widget (for rendering fractals). 我想创建自己的小部件类型(用于渲染分形)。 I have: 我有:

extern crate cairo;
extern crate gtk;

use cairo::Context;
use gtk::signal::Inhibit;
use gtk::signal::WidgetSignals;
use gtk::traits::ContainerTrait;
use gtk::traits::WidgetTrait;

struct MyWidget {
    widget: gtk::DrawingArea,
    foo: u32,
}

impl MyWidget {
    fn new() -> MyWidget {
        let result = MyWidget {
            widget: gtk::DrawingArea::new().unwrap(),
            foo: 17
        };
        result.widget.connect_draw(move |_w, c| {
            // Cannot do: result.redraw(c)
            Inhibit(true)
        });
        result
    }
    fn modify(&mut self, x: u32) {
        self.foo += x;
        self.widget.queue_draw();
    }
    fn redraw(&self, _ : Context) -> Inhibit {
        println!("Should redraw for {}", self.foo);
        Inhibit(true)
    }
}

fn main() {
    gtk::init().ok();
    let window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();

    let area = MyWidget::new();
    window.add(&area.widget);
    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });
    window.connect_key_release_event(move |_w, _event| {
        // Cannot do: area.modify(3);
        Inhibit(true)
    });
    window.connect_button_release_event(move |_w, _event| {
        // Cannot do: area.modify(17);
        Inhibit(true)
    });

    window.show_all();
    gtk::main();
}

But when redraw gets called, w is of course the gtk::DrawingArea and not my FractalWidget . 但是当redraw被调用时,w当然是gtk::DrawingArea而不是我的FractalWidget I have laborated with calling connect_draw with a closure, but not managed to use result in it (I have tried Box ing the result and move ing it into the lambda, but I'm new to this, so there is probably some way I haven't tried). 我已经laborated与调用connect_draw与闭合,而不是设法使用result在它(我曾经尝试Box荷兰国际集团的结果和move将其投入的拉姆达,但我是新来的这一点,所以有可能是一些方法我还没没试过)。

So, my actual question: Is there a way to either send more data into a rust-gnome redraw method (and other similar callbacks), or is there a way to extend a widget struct to contain my own data? 所以,我的实际问题是:有没有办法将更多数据发送到rust-gnome重绘方法(以及其他类似的回调),或者有没有办法扩展widget结构以包含我自己的数据?

Ok, here's some code that actually works, mainly by using Arc<Mutex<MyWidget>> insead of plain MyWidget . 好的,这里有一些实际Arc<Mutex<MyWidget>>的代码,主要是使用普通MyWidget Arc<Mutex<MyWidget>> MyWidget This still feels rather clumsy, as I need an explicit clone before moving into a closure and locking the mutex inside it, but this is probably good stuff to do (even if there is only one thread for gtk events). 这仍然感觉相当笨拙,因为我需要一个显式克隆才能进入闭包并将互斥锁锁定在其中,但这可能是好事(即使gtk事件只有一个线程)。 Maybe the verbosity can be fixed by a macro ... 也许宏观可以修复冗长...

extern crate cairo;
extern crate gtk;

use cairo::Context;
use gtk::signal::Inhibit;
use gtk::signal::WidgetSignals;
use gtk::traits::ContainerTrait;
use gtk::traits::WidgetTrait;
use std::sync::{Arc,Mutex};

struct MyWidget {
    widget: gtk::DrawingArea,
    foo: u32,
}

impl MyWidget {
    fn new() -> Arc<Mutex<MyWidget>> {
        let result = Arc::new(Mutex::new(MyWidget {
            widget: gtk::DrawingArea::new().unwrap(),
            foo: 17
        }));
        let r2 = result.clone();
        result.lock().unwrap().widget.connect_draw(move |_w, c| {
            r2.lock().unwrap().redraw(c)
        });
        result
    }
    fn modify(&mut self, x: u32) {
        self.foo += x;
        self.widget.queue_draw();
    }
    fn redraw(&self, _ : Context) -> Inhibit {
        println!("Should redraw for {}", self.foo);
        Inhibit(true)
    }
}

fn main() {
    gtk::init().ok();
    let window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();

    let area = MyWidget::new();
    window.add(&area.lock().unwrap().widget);
    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });
    let a1 = area.clone();
    window.connect_key_release_event(move |_w, _event| {
        a1.lock().unwrap().modify(3);
        Inhibit(true)
    });
    let a2 = area.clone();
    window.connect_button_release_event(move |_w, _event| {
        a2.lock().unwrap().modify(17);
        Inhibit(true)
    });

    window.show_all();
    gtk::main();
}

I'll wait at least a few days with marking this answer as correct, in case anyone has a better one. 我会等待至少几天,将此答案标记为正确,以防有人有更好的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM