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::SignalTimeout::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.
Here's an example of this technique:
Source location: examples/timeout/timeout.cc
#include <iostream> #include <gtkmm/button.h> #include <gtkmm/box.h> #include <gtkmm/main.h> #include <gtkmm/window.h> #include <map> class TimerExample : public Gtk::Window { // the usual stuff - nothing exciting Gtk::HBox m_box; Gtk::Button m_add_timer, m_del_timer, m_quit; int m_t_nr; // the start value for our timer static const int COUNT_VALUE; // the timeout value for the timers in [ms] static const int TIMEOUT_VALUE; // we need this to store our connections std::map<int,SigC::Connection> m_timers; // this is for storing our timer values // each timer countsa back from COUNT_VALUE to 0 and // if removed when it reaches 0 std::map<int,int> m_counters; public: TimerExample(); // the signal handlers for add & remove button void add_timer_pressed(); void del_timer_pressed(); // the signal handler for the timer // note that is not of the type int callback() // since we use bind() to add a data value of type int to it int timer_callback(int timer_nr); }; const int TimerExample::COUNT_VALUE = 5; const int TimerExample::TIMEOUT_VALUE = 1500; TimerExample::TimerExample() : m_add_timer("add a new timer"), m_del_timer("remove timer"), m_quit("Quit"), m_box(true,10), m_t_nr(0) { // connect the signal handlers m_quit.pressed.connect(&Gtk::Main::quit); m_add_timer.pressed.connect(slot(this,&TimerExample::add_timer_pressed)); m_del_timer.pressed.connect(slot(this,&TimerExample::del_timer_pressed)); // put buttons into container m_box.pack_start(m_add_timer); m_box.pack_start(m_del_timer); m_box.pack_start(m_quit); // set border and display all set_border_width(10); add(m_box); show_all(); } 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 int as return value after calling bind SigC::Slot0<int> my_slot = bind(slot(this,&TimerExample::timer_callback),m_t_nr); // now connect the slot to Gtk::Main::timeout Gtk::Connection conn = Gtk::Main::timeout.connect(my_slot,TIMEOUT_VALUE); // memorize connection m_timers[m_t_nr] = conn; // initialize timer count m_counters[m_t_nr] = COUNT_VALUE + 1; // print some information on the console cout << "added timeout " << m_t_nr++ << endl; } void TimerExample::del_timer_pressed() { // are there any timers ? if(m_timers.empty()) { // nope cout << "sorry, there are no timers left" << endl; } else { // get the nr of the first timer int timer_nr = m_timers.begin()->first; // give a little information to the user cout << "removing timer " << timer_nr << endl; // delete the entry in the counter values m_counters.erase(timer_nr); // destroy the connection !!!!! // this is important since the connection is NOT destroyed when // the according 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 // Try it and comment out the following line .... m_timers[timer_nr].disconnect(); // destroy the connection m_timers.erase(timer_nr); } } int TimerExample::timer_callback(int timer_nr) { // print the timernr cout << "This is timer " << timer_nr; // decrement & check counter value if(--m_counters[timer_nr] == 0) { cout << " boom" << endl; // delete the counter entry m_counters.erase(timer_nr); // delete the connection entry m_timers.erase(timer_nr); // note that we do not need to call disconnect on the connection // since we Gtk::Main does this for us when we return 0 return 0; } // print the timer value cout << " - " << m_counters[timer_nr] << "/" << COUNT_VALUE << endl; return 1; } // the intresting stuff ends here int main (int argc, char *argv[]) { Gtk::Main app(argc, argv); TimerExample example; app.run(); return 0; }