|
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;
}
|