You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GTK-rs中鼠标按下修改Pixbuf无效,求解决方法及合适事件方案

问题:左键点击修改Pixbuf不生效,Gesture是否合适?

我尝试在左键点击时修改Pixbuf,但修改似乎并未生效。modify_pixel函数用于获取Pixbuf的指定像素并对其进行修改。代码如下:

fn build_ui(application: &Application) {
    
    let pixbuf = Pixbuf::from_file("assets/map.png").expect("msg");
    let pixbuf = Rc::new(RefCell::new(pixbuf));
    
    let gesture = GestureClick::new();

    let pixbuf_clone = Rc::clone(&pixbuf);

    
    gesture.connect_pressed(move |_gesture, _n_press, x, y| {
        let mut pixbuf = pixbuf_clone.borrow_mut();
        let position = [x as usize, y as usize];
        if position[0] < pixbuf.width() as usize && position[1] < pixbuf.height() as usize {
            modify_pixel(&mut pixbuf, position);
        } else {
            println!("Out of bounds");
        }
    });

    let picture = Picture::for_pixbuf(Some(&pixbuf.borrow()).expect("No se pudo crear el Picture"));


    let window = ApplicationWindow::builder()
        .application(application)
        .default_height(800)
        .default_width(800)
        .title("My GTK App")
        .build();
    window.set_child(Some(&picture));
    window.add_controller(gesture);
    window.present();
}
fn modify_pixel(pixbuf: &mut Pixbuf, position: [usize;2]){
    let pixels = unsafe {pixbuf.pixels()};
    let rowstride = pixbuf.rowstride() as usize;
    let n_channels = pixbuf.n_channels() as usize;

    
    let offset = position[1] * rowstride + position[0] * n_channels;

    let mut pixels = pixels.to_vec(); 
    pixels[offset] = 255;  
    pixels[offset + 1] = 0;  
    pixels[offset + 2] = 0;  
    *pixbuf = Pixbuf::from_mut_slice(
        pixels,
        Colorspace::Rgb,
        pixbuf.has_alpha(),
        8, 
        pixbuf.width(),
        pixbuf.height(),
        rowstride as i32,
    );
}

另外,我不确定使用Gesture是否是最合适的选择。我也曾尝试在事件处理闭包内修改Picture,但遇到了同样的问题。


解决方案

1. 核心问题:Picture未同步Pixbuf的更新

你创建Picture时用的是初始的Pixbuf实例,之后修改Rc<RefCell<Pixbuf>>内部的Pixbuf,Picture不会自动感知到这个变化,必须手动调用picture.set_pixbuf()来更新显示。

2. 优化modify_pixel函数

原函数中pixels.to_vec()会复制整个像素缓冲区,效率很低,而且重新创建Pixbuf的操作没必要。可以直接修改原Pixbuf的像素数据(注意unsafe块的使用要确保安全):

fn modify_pixel(pixbuf: &Pixbuf, position: [usize;2]){
    let rowstride = pixbuf.rowstride() as usize;
    let n_channels = pixbuf.n_channels() as usize;
    let offset = position[1] * rowstride + position[0] * n_channels;

    // 直接修改原像素缓冲区,无需复制
    unsafe {
        let pixels = pixbuf.pixels();
        pixels[offset] = 255;
        pixels[offset + 1] = 0;
        pixels[offset + 2] = 0;
        // 如果有Alpha通道,可按需设置:pixels[offset +3] = 255;
    }
}

3. 修改build_ui函数,确保Picture更新

需要把picture也用Rc<RefCell>包裹,在回调中持有它的引用,修改完Pixbuf后手动更新:

fn build_ui(application: &Application) {
    
    let pixbuf = Pixbuf::from_file("assets/map.png").expect("msg");
    let pixbuf = Rc::new(RefCell::new(pixbuf));
    
    let gesture = GestureClick::new();

    // 同时克隆pixbuf和包裹picture的Rc
    let pixbuf_clone = Rc::clone(&pixbuf);
    let picture = Picture::for_pixbuf(Some(&pixbuf.borrow()).expect("No se pudo crear el Picture"));
    let picture_clone = Rc::new(RefCell::new(picture));

    gesture.connect_pressed(move |_gesture, _n_press, x, y| {
        let mut pixbuf = pixbuf_clone.borrow_mut();
        let position = [x as usize, y as usize];
        if position[0] < pixbuf.width() as usize && position[1] < pixbuf.height() as usize {
            modify_pixel(&pixbuf, position);
            // 修改后更新Picture的Pixbuf
            picture_clone.borrow_mut().set_pixbuf(Some(&pixbuf));
        } else {
            println!("Out of bounds");
        }
    });

    let window = ApplicationWindow::builder()
        .application(application)
        .default_height(800)
        .default_width(800)
        .title("My GTK App")
        .build();
    window.set_child(Some(&picture_clone.borrow()));
    window.add_controller(gesture);
    window.present();
}

关于Gesture的选择

GestureClick完全适合你的场景:它是GTK专门为点击类交互设计的高级手势控制器,相比直接监听button-press-event,它能自动处理双击、多点击等逻辑,还能过滤掉误触,是更推荐的做法。

内容的提问来源于stack exchange,提问作者zerowanderer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 02:50:55