Table of Contents
You may be wondering how to make gtkmm do useful work while it's idling along. 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::slot<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 that method. You receive a
sigc::connection
object that can be used to deactivate
the connection using its disconnect()
method:
my_connection.disconnect();
Another way of destroying the connection is your signal handler.
It has to be of the type sigc::slot<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" << std::endl; 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:
File: timerexample.h
(For use with gtkmm 4)
#ifndef GTKMM_EXAMPLE_TIMEREXAMPLE_H
#define GTKMM_EXAMPLE_TIMEREXAMPLE_H
#include <gtkmm.h>
#include <iostream>
#include <map>
class TimerExample : public Gtk::Window
{
public:
TimerExample();
protected:
// signal handlers
void on_button_add_timer();
void on_button_delete_timer();
void on_button_quit();
// This is the callback function the timeout will call
bool on_timeout(int timer_number);
// Member data:
Gtk::Box m_Box;
Gtk::Button m_ButtonAddTimer, m_ButtonDeleteTimer, m_ButtonQuit;
// Keep track of the timers being added:
int m_timer_number;
// These two constants are initialized in the constructor's member initializer:
const int count_value;
const int timeout_value;
// STL map for storing our connections
std::map<int, sigc::connection> m_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<int, int> m_counters;
};
#endif // GTKMM_EXAMPLE_TIMEREXAMPLE_H
File: main.cc
(For use with gtkmm 4)
#include "timerexample.h"
#include <gtkmm/application.h>
int main (int argc, char *argv[])
{
auto app = Gtk::Application::create("org.gtkmm.example");
return app->make_window_and_run<TimerExample>(argc, argv);
}
File: timerexample.cc
(For use with gtkmm 4)
#include "timerexample.h"
TimerExample::TimerExample() :
m_Box(Gtk::Orientation::HORIZONTAL, 10),
m_ButtonAddTimer("_Add", true),
m_ButtonDeleteTimer("_Remove", true),
m_ButtonQuit("_Quit", true),
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
{
m_Box.set_margin(10);
set_child(m_Box);
m_Box.append(m_ButtonAddTimer);
m_Box.append(m_ButtonDeleteTimer);
m_Box.append(m_ButtonQuit);
m_ButtonAddTimer.set_expand();
m_ButtonDeleteTimer.set_expand();
m_ButtonQuit.set_expand();
// Connect the three buttons:
m_ButtonQuit.signal_clicked().connect(sigc::mem_fun(*this,
&TimerExample::on_button_quit));
m_ButtonAddTimer.signal_clicked().connect(sigc::mem_fun(*this,
&TimerExample::on_button_add_timer));
m_ButtonDeleteTimer.signal_clicked().connect(sigc::mem_fun(*this,
&TimerExample::on_button_delete_timer));
}
void TimerExample::on_button_quit()
{
set_visible(false);
}
void TimerExample::on_button_add_timer()
{
// 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 sigc::bind.
sigc::slot<bool()> my_slot = sigc::bind(sigc::mem_fun(*this,
&TimerExample::on_timeout), m_timer_number);
// This is where we connect the slot to the Glib::signal_timeout()
auto conn = Glib::signal_timeout().connect(my_slot,
timeout_value);
// Remember 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::on_button_delete_timer()
{
// any timers?
if(m_timers.empty())
{
// no timers left
std::cout << "Sorry, there are no timers left." << std::endl;
}
else
{
// get the number of the first timer
int timer_number = m_timers.begin()->first;
// Give some info to the user:
std::cout << "manually disconnecting timer " << timer_number
<< std::endl;
// Remove the entry in the counter values
m_counters.erase(timer_number);
// Diconnect the signal handler:
m_timers[timer_number].disconnect();
// Forget the connection:
m_timers.erase(timer_number);
}
}
bool TimerExample::on_timeout(int timer_number)
{
// Print the timer:
std::cout << "This is timer " << timer_number;
// decrement and check counter value
if (--m_counters[timer_number] == 0)
{
std::cout << " being disconnected" << std::endl;
// delete the counter entry in the STL MAP
m_counters.erase(timer_number);
// delete the connection entry in the STL MAP
m_timers.erase(timer_number);
// 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_number] << "/"
<< count_value << std::endl;
// Keep going (do not disconnect yet):
return true;
}