Event propagation means that, when an event is emitted on a particular widget, it can be passed to its parent widget (and that widget can pass it to its parent, and so on) and, if the parent has an event handler, that handler will be called.
The event will propagate until it reaches the top-level widget, or until
you stop the propagation by returning true
from an
event handler.
Notice, that after canceling an event, no other function will be called (even if it is from the same widget).
In this example there are three event handlers, one in the
Gtk::Entry
, one in the Gtk::Grid
and one in the Gtk::Window
.
When you write in the entry, a key release event will be emitted first
in the Entry
and, depending on whether we let
it propagate, it can reach the Grid
's and the
Window
's event handlers. If it propagates,
the text you're writing will appear in the Label
above the Entry
.
File: examplewindow.h
(For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EVENT_PROPAGATION_H #define GTKMM_EVENT_PROPAGATION_H #include <gtkmm.h> #include <iostream> class ExampleWindow : public Gtk::Window { public: ExampleWindow(); virtual ~ExampleWindow(); private: bool entryKeyRelease(GdkEventKey *event); bool gridKeyRelease(GdkEventKey *event); bool windowKeyRelease(GdkEventKey *event); Gtk::Grid m_container; Gtk::Label m_label; Gtk::Entry m_entry; Gtk::CheckButton m_checkbutton_can_propagate; }; #endif //GTKMM_EVENT_PROPAGATION_H
File: examplewindow.cc
(For use with gtkmm 3, not gtkmm 2)
#include "examplewindow.h" ExampleWindow::ExampleWindow() { add(m_container); set_title("Event Propagation"); set_border_width(10); m_label.set_label("A label"); m_checkbutton_can_propagate.set_label("Can Propagate"); m_checkbutton_can_propagate.set_active(); // Main Container m_container.set_orientation(Gtk::ORIENTATION_VERTICAL); m_container.add(m_label); m_container.add(m_entry); m_container.add(m_checkbutton_can_propagate); // Events add_events(Gdk::KEY_RELEASE_MASK); m_entry.signal_key_release_event().connect( sigc::mem_fun(*this, &ExampleWindow::entryKeyRelease)); m_container.signal_key_release_event().connect( sigc::mem_fun(*this, &ExampleWindow::gridKeyRelease)); signal_key_release_event().connect( sigc::mem_fun(*this, &ExampleWindow::windowKeyRelease)); show_all_children(); } //By changing the return value we allow, or don't allow, the event to propagate to other elements. bool ExampleWindow::entryKeyRelease(GdkEventKey* /* event */ ) { std::cout << "Entry" << std::endl; if(m_checkbutton_can_propagate.get_active()) { return false; } return true; } bool ExampleWindow::gridKeyRelease(GdkEventKey* /* event */ ) { std::cout << "Grid" << std::endl; //Let it propagate: return false; } // This will set the entry's text in the label, every time a key is pressed. bool ExampleWindow::windowKeyRelease(GdkEventKey* /* event */ ) { std::cout << "Window" << std::endl; //checking if the entry is on focus, otherwise the label would get changed by pressing keys //on the window (when the entry is not on focus), even if canPropagate wasn't active if(m_entry.has_focus()) { m_label.set_text(m_entry.get_text()); } return true; } ExampleWindow::~ExampleWindow() { }
File: main.cc
(For use with gtkmm 3, not gtkmm 2)
#include "examplewindow.h" #include <gtkmm/main.h> int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); ExampleWindow window; //Shows the window and returns when it is closed. Gtk::Main::run(window); return 0; }