I am working on a GTK-rs application in Rust that includes a drawing area. I am trying to print the position of the cursor to the command line whenever the user hovers over the drawing area. I have tried using the motion notify event with a callback function that retrieves the x and y coordinates of the event using the position() method, and then prints them to the console using println!(). However, when I run the application and hover over the drawing area, nothing is printed to the console.
Here is the Rust code I am using:
use cairo::{ImageSurface, Context, Format};
use gtk::prelude::*;
use gtk::{Builder, Window, DrawingArea};
fn main() {
if let Err(err) = gtk::init() {
println!("Failed to initialize GTK: {}", err);
return;
}
let glade_src = include_str!("interface.ui");
let builder = Builder::from_string(glade_src);
let window: Window = builder.object("main").unwrap();
let drawing: DrawingArea = builder.object("canvas").unwrap();
let surface = ImageSurface::create(Format::ARgb32, 600, 700).unwrap();
drawing.connect_draw(move |_,cr| {
let surface_ctx = Context::new(&surface).unwrap();
surface_ctx.set_source_rgb(1.0,1.0,1.0);
surface_ctx.paint().expect("unable to paint surface_ctx");
cr.set_source_surface(&surface, 0.0, 0.0).expect("unable to set source surface");
cr.paint().expect("unable to paint context");
Inhibit(false)
});
drawing.connect_motion_notify_event(|_widget, event| {
let x = event.position().0;
let y = event.position().1;
println!("Mouse click position: ({}, {})", x, y);
Inhibit(false)
});
window.show_all();
gtk::main();
}
Here's the interface.ui:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkWindow" id="main">
<property name="can-focus">False</property>
<child>
<object class="GtkPaned">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="position">400</property>
<child>
<object class="GtkDrawingArea" id="canvas">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">A scaled down version
of the interface.ui</property>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
I have tried using the button_press_event
signal, the motion_notify_event
, and drawing.grab_focus()
to capture mouse events, but none of these methods have worked for me.
I expected that when I hovered over the drawing area, my program would print the position of the cursor to the console. However, nothing is being printed when I hover over the drawing area.
Any suggestions on how to make this work or what I am missing would be greatly appreciated.
I did a bit of research and came across this Python answer to a similar problem, which shows that you need to set up the DrawingArea
in order for it to receive events. So in your code, you would use gdk
to set up the POINTER_MOTION_MASK
, like so:
drawing.set_events(gdk::EventMask::POINTER_MOTION_MASK);
So your complete program will look like this:
use gtk::cairo::{ImageSurface, Context, Format};
use gtk::prelude::*;
use gtk::{Builder, Window, DrawingArea};
use gdk;
fn main() {
if let Err(err) = gtk::init() {
println!("Failed to initialize GTK: {}", err);
return;
}
let glade_src = include_str!("interface.ui");
let builder = Builder::from_string(glade_src);
let window: Window = builder.object("main").unwrap();
let drawing: DrawingArea = builder.object("canvas").unwrap();
let surface = ImageSurface::create(Format::ARgb32, 600, 700).unwrap();
drawing.connect_draw(move |_,cr| {
let surface_ctx = Context::new(&surface).unwrap();
surface_ctx.set_source_rgb(1.0,1.0,1.0);
surface_ctx.paint().expect("unable to paint surface_ctx");
cr.set_source_surface(&surface, 0.0, 0.0).expect("unable to set source surface");
cr.paint().expect("unable to paint context");
Inhibit(false)
});
drawing.set_events(gdk::EventMask::POINTER_MOTION_MASK);
drawing.connect_motion_notify_event(|_widget, event| {
let x = event.position().0;
let y = event.position().1;
println!("Mouse click position: ({}, {})", x, y);
Inhibit(false)
});
window.show_all();
gtk::main();
}
The program will output the cursor position when the mouse moves over the drawing area, as intended.