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

为何GestureMultiPress无法识别我的鼠标点击操作?

问题描述

我正在用gtk-rs(GTK+ 3)开发小型应用,遇到了鼠标点击无法被识别的问题。我有一个DrawingArea,希望每次在该区域内点击鼠标时执行特定代码,选择用GestureMultiPress(因为这是更现代的方式,而非直接处理事件),但配置后完全没有输出。

我的配置代码片段:

let drw_area : DrawingArea  = ...;
...
window.add(&drw_area);
...
window.add_events(EventMask::BUTTON_PRESS_MASK | EventMask::BUTTON_RELEASE_MASK);
let press =
  GestureMultiPress::builder()
    .button(0)
    .widget(&drw_area)
    .build();
let _press_handler_id = {
  press.connect_pressed(|g, npress, x, y| {
    println!("({}, {npress}, {x}, {y})", g.current_button());
  })
};

完整代码:

use gtk::gdk::EventMask;
use gtk::prelude::*;
use gtk::{DrawingArea, GestureMultiPress};

const APP_NAME : &'static str = "com.example.appname";
const APP_TITLE : &'static str = "Example App";

const APP_WIDTH : i32 = 600;
const APP_HEIGHT : i32 = 600;
const APP_BORDER_WIDTH : u32 = 20;

fn build_ui(application : &gtk::Application) {
  let window = gtk::ApplicationWindow::new(application);

  window.set_title(APP_TITLE);
  window.set_border_width(APP_BORDER_WIDTH);
  window.set_position(gtk::WindowPosition::Center);
  window.set_default_size(APP_WIDTH, APP_HEIGHT);

  let drw_area = {
    DrawingArea::builder()
      .width_request(APP_WIDTH - 2*APP_BORDER_WIDTH as i32)
      .height_request(APP_HEIGHT - 2*APP_BORDER_WIDTH as i32)
      .build()
  };

  drw_area.connect_draw(|a, c| {
    c.set_source_rgb(0.0, 0.0, 0.0);
    c.rectangle(0.0, 0.0, a.allocated_width() as f64, a.allocated_height() as f64);
    let _ = c.fill();
   Inhibit(false) 
  });
  window.add(&drw_area);

  window.add_events(EventMask::BUTTON_PRESS_MASK | EventMask::BUTTON_RELEASE_MASK);
  let press =
    GestureMultiPress::builder()
      .button(0)
      .widget(&drw_area)
      .build();
  let _press_handler_id = {
    press.connect_pressed(|g, npress, x, y| {
      println!("({}, {npress}, {x}, {y})", g.current_button());
    })
  };
 
  window.show_all();
}

fn main() {
  let application =
    gtk::Application::new(Some(APP_NAME), Default::default());
  application.connect_activate(build_ui);
  application.run();
}
问题原因
  1. 手势对象生命周期过短:创建的GestureMultiPress是局部变量,build_ui函数执行完毕后,该变量会被销毁,导致手势无法继续监听事件。
  2. 多余的事件掩码设置:给window添加BUTTON_PRESS_MASK和BUTTON_RELEASE_MASK是不必要的,GTK手势机制会自动处理事件的捕获,手动添加反而可能引发冲突。
修复方案

步骤1:持久化手势对象

将手势对象附加到DrawingArea上,利用GTK的对象数据存储机制让其随DrawingArea的生命周期存在,使用set_data方法绑定即可。

步骤2:移除多余的事件掩码设置

删除window.add_events(...)这一行代码。

修复后的完整代码:

use gtk::prelude::*;
use gtk::{DrawingArea, GestureMultiPress};

const APP_NAME : &'static str = "com.example.appname";
const APP_TITLE : &'static str = "Example App";

const APP_WIDTH : i32 = 600;
const APP_HEIGHT : i32 = 600;
const APP_BORDER_WIDTH : u32 = 20;

fn build_ui(application : &gtk::Application) {
  let window = gtk::ApplicationWindow::new(application);

  window.set_title(APP_TITLE);
  window.set_border_width(APP_BORDER_WIDTH);
  window.set_position(gtk::WindowPosition::Center);
  window.set_default_size(APP_WIDTH, APP_HEIGHT);

  let drw_area = {
    DrawingArea::builder()
      .width_request(APP_WIDTH - 2*APP_BORDER_WIDTH as i32)
      .height_request(APP_HEIGHT - 2*APP_BORDER_WIDTH as i32)
      .build()
  };

  drw_area.connect_draw(|a, c| {
    c.set_source_rgb(0.0, 0.0, 0.0);
    c.rectangle(0.0, 0.0, a.allocated_width() as f64, a.allocated_height() as f64);
    let _ = c.fill();
    Inhibit(false) 
  });
  window.add(&drw_area);

  // 创建手势并绑定到DrawingArea
  let press =
    GestureMultiPress::builder()
      .button(0)
      .widget(&drw_area)
      .build();
  
  press.connect_pressed(|g, npress, x, y| {
    println!("({}, {npress}, {x}, {y})", g.current_button());
  });

  // 将手势对象附加到DrawingArea,保证其生命周期
  drw_area.set_data("press_gesture", press);
 
  window.show_all();
}

fn main() {
  let application =
    gtk::Application::new(Some(APP_NAME), Default::default());
  application.connect_activate(build_ui);
  application.run();
}

额外说明

  • .button(0)表示监听所有鼠标按钮,如果你只想监听特定按钮(比如左键是1,右键是3),可以修改为对应数字。
  • 默认情况下DrawingArea可以接收鼠标事件,若有特殊需求,可添加drw_area.set_can_focus(true)和drw_area.set_receives_default(true)确保交互性。

内容的提问来源于stack exchange,提问作者V. Jackson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 08:25:15