アイドル関数

あるメソッドを何も起きていないときに呼ばれるように設定するには、次の関数を使ってください:

sigc::connection  Glib::Main::SignalIdle::connect(const Slot<int>& idlefunc, int priority);

これを行うとgtkmmは指定されたメソッドを、他になにも起きていないときに呼び出すようになります。優先度の設定を追加することもできます(数字が小さいほど高優先度)。なにも指定しない場合はGtk::PRIORITY_DEFAULT(デフォルトの優先度)が使われます。シグナルハンドラへの接続を除去する方法は二つあります: 返り値のsigc::connectionオブジェクトのdisconnect()を呼ぶか、シグナルハンドラでfalse(あるいは0)を返すかです。シグナルハンドラは次のように宣言する必要があります:

int idleFunc();

これは以前のメソッドのものとほとんど同じですので、動作を理解するのに説明はもう十分でしょう。とはいえ、ちょっとした例を挙げておきます:

Source Code

File: idleexample.h

#ifndef GTKMM_EXAMPLE_IDLEEXAMPLE_H
#define GTKMM_EXAMPLE_IDLEEXAMPLE_H

#include <gtkmm.h>
#include <iostream>

class IdleExample : public Gtk::Window
{
public:
  IdleExample();

protected:
  // Signal Handlers:
  bool on_timer();
  bool on_idle();
  void on_button_clicked();

  // Member data:
  Gtk::VBox m_Box;
  Gtk::Button m_ButtonQuit;
  Gtk::ProgressBar m_ProgressBar_c;
  Gtk::ProgressBar m_ProgressBar_d;
};

#endif // GTKMM_EXAMPLE_IDLEEXAMPLE_H

File: main.cc

#include "idleexample.h"
#include <gtkmm/main.h>

int main (int argc, char *argv[])
{
  Gtk::Main app(argc, argv);

  IdleExample example;
  Gtk::Main::run(example);

  return 0;
}

File: idleexample.cc

#include "idleexample.h"

IdleExample::IdleExample() :
  m_Box(false, 5),
  m_ButtonQuit(Gtk::Stock::QUIT)
{
  set_border_width(5);

  // Put buttons into container

  // Adding a few widgets:
  add(m_Box);
  m_Box.pack_start( *Gtk::manage(new Gtk::Label("Formatting Windows drive C:")));
  m_Box.pack_start( *Gtk::manage(new Gtk::Label("100 MB")) );
  m_Box.pack_start(m_ProgressBar_c);

  m_Box.pack_start( *Gtk::manage(new Gtk::Label("")) );

  m_Box.pack_start( *Gtk::manage(new Gtk::Label("Formatting Windows drive D:")));
  m_Box.pack_start( *Gtk::manage(new Gtk::Label("5000 MB")) );
  m_Box.pack_start(m_ProgressBar_d);

  Gtk::HBox* hbox = Gtk::manage( new Gtk::HBox(false,10));
  m_Box.pack_start(*hbox);
  hbox->pack_start(m_ButtonQuit, Gtk::PACK_EXPAND_PADDING);

  // Connect the signal handlers:
  m_ButtonQuit.signal_clicked().connect( sigc::mem_fun(*this,
              &IdleExample::on_button_clicked) );

  // formatting drive c in timeout signal handler - called once every 50ms
  Glib::signal_timeout().connect( sigc::mem_fun(*this, &IdleExample::on_timer),
          50 );

  // formatting drive d in idle signal handler - called as quickly as possible
  Glib::signal_idle().connect( sigc::mem_fun(*this, &IdleExample::on_idle) );

  show_all_children();
}


void IdleExample::on_button_clicked()
{
  hide();
}

// this timer callback function is executed once every 50ms (set in connection
// above).  Use timeouts when speed is not critical. (ie periodically updating
// something).
bool IdleExample::on_timer()
{
  double value = m_ProgressBar_c.get_fraction();

  // Update progressbar 1/500th each time:
  m_ProgressBar_c.set_fraction(value + 0.002);
 
  return value < 0.99;  // return false when done
}


// This idle callback function is executed as often as possible, hence it is
// ideal for processing intensive tasks.
bool IdleExample::on_idle()
{
  double value = m_ProgressBar_d.get_fraction();

  // Update progressbar 1/5000th each time:
  m_ProgressBar_d.set_fraction(value + 0.0002);

  return value < 0.99;  // return false when done
}

このコード例ではアイドリング関数とタイムアウト関数の違いをいくつか見せています。あるメソッドを定期的に呼ぶ必要があるが、その間隔はそれほど重要ではないときはタイムアウト関数がいいでしょう。あるメソッドを出来るだけ何度も呼ぶ必要があるとき(例えば、フラクタルをバックグラウンドで計算するとき)は、アイドリング関数を使ってください。

コード例を実行しながら、システム負荷を上げてみてください。上のプログレスバーは着実に増加しますが、下のものはペースダウンするはずです。