Table of Contents
You may be wondering how to make gtkmm do useful work while it's idling along (well, sleeping actually) in Gtk::Main::run(). Happily, you have several options. Using the following methods you can create a timeout method that will be called every few milliseconds.
SigC::Connection Glib::signal_timeout().connect(const SigC::Slot0<bool>& slot, unsigned int interval, int priority = Glib::PRIORITY_DEFAULT);
The first argument is a slot you wish to have called when the timeout occurs. The second argument is the number of milliseconds between calls to your method. You get back a SigC::Connection object that can be used to destroy the connection. Use
MyConnection.disconnect();
to destroy the connection. Another way of destroying the Connection is your signal handler. It has to be of the type SigC::Slot0<bool>. As you see from the definition your signal handler has to return a value of the type bool. A definition of a sample method might look like this:
bool MyCallback() { std::cout << "Hello World!\n"; return true; }
You can stop the timeout method by returning false from your signal handler. Therefore, if you want your method to be called repeatedly, it should return true.
The following is an example of this technique, broken into three separate source files:
Source location: examples/timeout/timeout.h
#ifndef TIMEOUT_H #define TIMEOUT_H // Its more memory efficient to only include the header files that your // application will need rather than including <gtkmm.h> #include <iostream> #include <gtkmm/box.h> #include <tkmm/button.h> #include <gtkmm/window.h> #include <map> class TimerExample : public Gtk::Window { public: TimerExample(); void add_timer_pressed(); void del_timer_pressed(); bool timer_callback(int timer_nr); protected: Gtk::HBox m_box; // Buttons for adding & deleting a timer and quitting the app Gtk::Button m_add_timer, m_del_timer, m_quit; // keep track of the timers being added int m_timer_number; // these two constants are initialized in the member initializer const int COUNT_VALUE; const int TIMEOUT_VALUE; // STL map for storing our connections std::mapm_timers; // STL map for storing our timer values // each timer counts back from COUNT_VALUE to 0 and // is removed when it reaches 0 std::map m_counters; }; #endif
Source location: examples/timeout/timeout.cpp
#include "timeout.h" TimerExample::TimerExample() : m_add_timer("add a new timer"), m_del_timer("remove timer"), m_quit("Quit"), m_box(true,10), m_timer_number(0), // start numbering the timers at 0 COUNT_VALUE(5), // each timer will count down 5 times before disconnecting TIMEOUT_VALUE(1500) // 1500 ms = 1.5 seconds { // connect the three buttons m_quit.signal_pressed().connect(SigC::slot(*this, &Gtk::Widget::hide)); m_add_timer.signal_pressed().connect(SigC::slot(*this,&TimerExample::add_timer_pressed)); m_del_timer.signal_pressed().connect(SigC::slot(*this,&TimerExample::del_timer_pressed)); m_box.pack_start(m_add_timer); m_box.pack_start(m_del_timer); m_box.pack_start(m_quit); set_border_width(10); add(m_box); show_all(); // show all the widgets, including the top level container } void TimerExample::add_timer_pressed() { // creation of a new object prevents long lines and shows us a little // how slots work. We have 0 parameters and bool as a return value // after calling bind. SigC::Slot0<bool> my_slot = bind(SigC::slot(*this,&TimerExample::timer_callback), m_timer_number); // This is where we connect the slot to the Glib::signal_timeout() SigC::Connection conn = Glib::signal_timeout().connect(my_slot,TIMEOUT_VALUE); // memorize the connection m_timers[m_timer_number] = conn; // initialize timer count m_counters[m_timer_number] = COUNT_VALUE + 1; // print some info to the console for the user std::cout << "added timeout " << m_timer_number++ << std::endl; } void TimerExample::del_timer_pressed() { // any timers? if(m_timers.empty()) { // no timers left std::cout << "Sorry, there are no timers left!" << std::endl; } else { // get the nr of the first timer int timer_nr = m_timers.begin()->first; // give some info to the user std::cout << "manually disconnecting timer " << timer_nr << std::endl; // delete the entry in the counter values m_counters.erase(timer_nr); // destroy the connection!! // ***This is very important since the connection is NOT destroyed when // the corresponding Connection-Object is deleted. The purpose of the // connection object is to give you the possibility to destroy a // connection without having to destroy either the sender or the receiver. // (ie. since we are destroying the connection early, we must actually // call the disconnect() method on the connection object). // Try it and comment out the following line .... m_timers[timer_nr].disconnect(); // destroy the connection m_timers.erase(timer_nr); } } bool TimerExample::timer_callback(int timer_nr) { // print the timer std::cout << "This is timer " << timer_nr; // decrement and check counter value if (--m_counters[timer_nr] == 0) { std::cout << " being disconnected" << std::endl; // delete the counter entry in the STL MAP m_counters.erase(timer_nr); // delete the connection entry in the STL MAP m_timers.erase(timer_nr); // ***Note that we do not have to explicitly call disconnect() on the connection // since Gtk::Main does this for us when we return false. return false; } // print the timer value std::cout << " - " << m_counters[timer_nr] << "/" << COUNT_VALUE << std::endl; // keep going (ie. do not disconnect yet!) return true; }
Source location: examples/timeout/main.cpp
#include <gtkmm/main.h> #include "timeout.h" int main(int argc, char *argv[]) { Gtk::Main kit(argc,argv); TimerExample example; Gtk::Main::run(example); return 0; }