Fonctions à délai échu

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

Le premier paramètre est un objet slot appelé quand le délai est échu. Le deuxième argument est le nombre de millisecondes entre chaque appel de la fonction. Vous recevez en retour un objet sigc::connection qu'il est possible d'utiliser pour désactiver la connexion à l'aide de sa fonction membre disconnect() :

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

Vous pouvez arrêter l'appel périodique de la fonction en renvoyant false à partir du gestionnaire de signal. Mais si vous voulez que la fonction soit réitérée, il faut qu'elle renvoie true.

Voici un exemple de cette technique :

Source Code

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()
{
  hide();
}

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