JShorthouse
JShorthouse

Reputation: 1670

Making a clickable box in GTK4

How can I make a gtk4::Box clickable in gtk_rs?

In GTK3 it seems that using an EventBox was the way to achieve this, however in GTK4:

Stop using GtkEventBox

GtkEventBox is no longer needed and has been removed.

All widgets receive all events.

https://docs.gtk.org/gtk4/migrating-3to4.html#stop-using-gtkeventbox

So it seems that click handlers should now be attached to widgets directly. However I can't find any clear documentation or examples on how to do this.

If someone could give me an example of attaching a click listener to a gtk4::Box it would be much appreciated.

Upvotes: 5

Views: 1675

Answers (1)

frankenapps
frankenapps

Reputation: 8281

You can do this using gtk::GestureClick like shown in this example.

Here is a full example (click somewhere inside the window as the box is not actually visible):

use gtk::prelude::*;
use gtk::{Application, ApplicationWindow};

fn main() {
    // Create a new application
    let app = Application::builder()
        .application_id("org.gtk-rs.example")
        .build();

    // Connect to "activate" signal of `app`
    app.connect_activate(|app| {
        build_ui(app);
    });

    // Run the application
    app.run();
}

fn build_ui(app: &Application) {
    // Create a window and set the title
    let window = ApplicationWindow::builder()
        .application(app)
        .title("My GTK App")
        .build();

    // Create a box
    let gtk_box = gtk::builders::BoxBuilder::new()
        .height_request(200)
        .width_request(300)
        .build();

    // Assign a click listener
    let gesture = gtk::GestureClick::new();
    gesture.connect_released(|gesture, _, _, _| {
        gesture.set_state(gtk::EventSequenceState::Claimed);
        println!("Box pressed!");
    });
    gtk_box.add_controller(&gesture);

    // Add the box
    window.set_child(Some(&gtk_box));

    // Present window to the user
    window.present();
}

A more involved example

Say you wanted to actually also see the box and maybe provide some user feedback on mouse hover. Then you will need to use CSS rules to achieve that.

Change your main.rs to:

use gtk::gdk::Display;
use gtk::{CssProvider, StyleContext, prelude::*};
use gtk::{Application, ApplicationWindow};

fn main() {
    // Create a new application
    let app = Application::builder()
        .application_id("org.gtk-rs.example")
        .build();

    // Connect to "activate" signal of `app`
    app.connect_activate(|app| {
        // Load a CSS stylesheet from the included bytes.
        let provider = CssProvider::new();
        provider.load_from_data(include_bytes!("style.css"));

        // Give the CssProvider to the default screen so the CSS rules are
        // applied to the window.
        StyleContext::add_provider_for_display(
            &Display::default().expect("Error initializing gtk css provider."),
            &provider,
            gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
        );

        build_ui(app);
    });

    // Run the application
    app.run();
}

fn build_ui(app: &Application) {
    // Create a window and set the title
    let window = ApplicationWindow::builder()
        .application(app)
        .title("My GTK App")
        .build();

    // Create a box
    let gtk_box = gtk::builders::BoxBuilder::new()
        .height_request(200)
        .width_request(300)
        .margin_bottom(20)
        .margin_end(20)
        .margin_start(20)
        .margin_top(20)
        .css_classes(vec![String::from("hover-box")])
        .build();

    // Assign a click listener
    let gesture = gtk::GestureClick::new();
    gesture.connect_released(|gesture, _, _, _| {
        gesture.set_state(gtk::EventSequenceState::Claimed);
        println!("Box pressed!");
    });
    gtk_box.add_controller(&gesture);

    // Add the box
    window.set_child(Some(&gtk_box));

    // Present window to the user
    window.present();
}

and create a style.css file in the src/ directory (the same directory where the main.rs is located) with this content:

.hover-box {
    background-color: blue;
    border-radius: 5px;
}

.hover-box:hover {
    background-color: rgb(11, 133, 240);
    border-radius: 5px;
}

Now you get a gtk4::Box with a 5px border radius and blue background color that changes when you hover the mouse above the box.

Upvotes: 8

Related Questions