3

...或者,我如何子类化 gtk::Widget?

我的 中有以下依赖项Cargo.toml

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

我想创建自己的小部件类型(用于渲染分形)。我有:

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();
}

但是当redraw被调用时, w 当然是 thegtk::DrawingArea而不是 my FractalWidget。我已经尝试使用闭包进行调用connect_draw,但没有设法在result其中使用(我尝试过Box将结果move输入到 lambda 中,但我对此很陌生,所以可能有一些我没有尝试过的方法) .

所以,我的实际问题是:有没有办法将更多数据发送到 rust-gnome 重绘方法(和其他类似的回调),或者有没有办法扩展小部件结构以包含我自己的数据?

4

1 回答 1

2

好的,这是一些实际有效的代码,主要是使用Arc<Mutex<MyWidget>>insead 或 plain MyWidget。这仍然感觉相当笨拙,因为在进入闭包并将互斥锁锁定在其中之前,我需要一个显式克隆,但这可能是一件好事(即使只有一个线程用于 gtk 事件)。也许冗长可以通过宏来修复......

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();
}

我将至少等待几天将此答案标记为正确,以防有人有更好的答案。

于 2015-07-26T17:31:53.287 回答