本家のオンラインマニュアル

タイマーイベント

 一定の時間間隔をおいて繰り返す処理を実現するには forや while などのループを使用するというのがオーソドックスな考え方かもしれませんが, GUIアプリ構築においてはタイマーイベントを仕掛ける形で処理を実現するのが標準的な方法です. ウィンドウなどのGUIの要素には一定間隔毎にタイミング信号(タイマーイベント)を与えることができ, これを受信したGUI要素はイベント処理を発動します.

 ここでは,一定の時間間隔でタイマーイベントを発するタイマーと呼ばれるものについてと, それに反応してイベント処理をする方法について説明します.


■ 簡単な時計アプリ

 wxWidgetsには設定された時間間隔毎にタイマーイベントを発生させる タイマーオブジェクト (wxTimerクラス)があり,このタイマーオブジェクトをメンバとして持つGUI要素は, タイマーをイベントとする処理を発動することができます. 一定の時間間隔毎に時刻を表示する時計を実現するプログラムを例にタイマーイベントの使い方について説明します.

 下のプログラム 'DateTime.cpp' を見てください.

プログラム全体:DateTime.cpp
#include <wx/wx.h>

//-------------------------------------------------------
// Application Frame Window
//-------------------------------------------------------

//--- Class ---
class frameClass: public wxFrame {
  public:
    frameClass(int id, const wxString& title);
    virtual void On_mQuit(wxCommandEvent &event);
    virtual void OnTimer(wxTimerEvent &event);
    
  private:
    wxMenuBar* menubar;
    wxStaticText* lb1;
    wxTextCtrl* tfDate;
    wxStaticText* lb2;
    wxTextCtrl* tfTime;
    
    wxTimer timer;

    DECLARE_EVENT_TABLE();
}; 

//--- Constructor ---
frameClass::frameClass(int id, const wxString& title)
  :wxFrame(NULL, id, title), timer(this,20001)
{
    menubar = new wxMenuBar();
    wxMenu* mFile = new wxMenu();
    mFile->Append(10101, wxT("Quit"));
    menubar->Append(mFile, wxT("File"));
    SetMenuBar(menubar);

    lb1 = new wxStaticText(this, wxID_ANY, wxT("Date"));
    tfDate = new wxTextCtrl(this, 10201);
    tfDate->SetMinSize(wxSize(250,40));

    lb2 = new wxStaticText(this, wxID_ANY, wxT("Time"));
    tfTime = new wxTextCtrl(this, 10202);
    tfTime->SetMinSize(wxSize(250,40));

    lb1->SetFont(wxFont(14, wxROMAN, wxNORMAL, wxNORMAL, 0, wxT("")));
    tfDate->SetFont(wxFont(20, wxROMAN, wxNORMAL, wxNORMAL, 0, wxT("")));

    lb2->SetFont(wxFont(14, wxROMAN, wxNORMAL, wxNORMAL, 0, wxT("")));
    tfTime->SetFont(wxFont(20, wxROMAN, wxNORMAL, wxNORMAL, 0, wxT("")));

    wxBoxSizer* sizer1 = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* sizer3 = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL);
    sizer1->Add(lb1, 0, wxEXPAND, 0);
    sizer2->Add(tfDate, 0, 0, 0);
    sizer1->Add(sizer2, 0, 0, 0);
    sizer1->Add(lb2, 0, wxEXPAND, 0);
    sizer3->Add(tfTime, 0, 0, 0);
    sizer1->Add(sizer3, 1, wxEXPAND, 0);
    SetSizer(sizer1);
    sizer1->Fit(this);
    Layout();

    timer.Start(500);
}

//--- Event Handling ---
BEGIN_EVENT_TABLE(frameClass, wxFrame)
    EVT_MENU( 10101, frameClass::On_mQuit)
    EVT_TIMER(20001, frameClass::OnTimer)
END_EVENT_TABLE();

void frameClass::OnTimer(wxTimerEvent &event)
{
    int yy, mm, dd, wd, hour, min, sec;
    wxString s;

    event.Skip();

    wxDateTime dt;
    dt = wxDateTime::Now();

    yy = dt.GetYear();
    mm = dt.GetMonth() + 1;
    dd = dt.GetDay();
    wd = dt.GetWeekDay();
    s.Printf(wxT("%d / %d / %d (%d)"),yy,mm,dd,wd);
    tfDate->SetValue(s);

    hour = dt.GetHour();
    min  = dt.GetMinute();
    sec  = dt.GetSecond();
    s.Printf(wxT("%d : %d : %d"),hour,min,sec);
    tfTime->SetValue(s);
}

void frameClass::On_mQuit(wxCommandEvent &event)
{
    event.Skip();

    Close();
}

//-------------------------------------------------------
// Application
//-------------------------------------------------------

//--- Class ---
class appClass: public wxApp {
  public:
    bool OnInit();
};

IMPLEMENT_APP(appClass)

bool appClass::OnInit()
{
    frameClass* frame = new frameClass(wxID_ANY, wxEmptyString);
    SetTopWindow(frame);
    frame->Show();
    return true;
}

 このプログラムで定義されている 'frameClass' は時計のウィンドウで, 日付を表示するテキストフィールド 'wxTextCtrl* tfDate' と, 時刻を表示するテキストフィールド 'wxTextCtrl* tfTime' を持ちます. また,一定間隔のタイマーイベントを発するタイマーオブジェクト 'wxTimer timer' をメンバーとして持っており,言ってみればこれがイベントの発信源というわけです. また,frameClassクラスのコンストラクタにtimer(this,20001)という記述がありますが, これはframeClassオブジェクトを生成する際にtimerの所属するウィンドウと, タイマーのID(20001)をセットするものです.また,コンストラクタの最後に記述されている 'timer.Start(500);' は,「500ミリ秒毎にタイマーイベントを繰り返し発生させる」という設定です.

 タイマーイベントを受けて動作するイベントハンドラは 'OnTimer' で, この関数の中に処理(現在の日付と時刻の表示)を記述しています.

● 日付と時刻の取得

 現在の日付と時刻を与えるオブジェクトというもの(wxDateTimeクラス)が存在し, それに対して 'Now()' などの関数を実行することで日付や時刻の値を得ることができます. プログラム中の

  wxDateTime dt;
  dt = wxDateTime::Now();

という記述がそれに当たる部分で,これを実行することでdtに日付と時刻の情報が格納されます. このdtから年,月,日,曜日,時,分,秒の数値を取り出すには下記のような関数を使います.

  関数 取得するもの
  GetYear() 西暦年
  GetMonth() 「月-1」の値
  GetDay() 「日」の値
  GetWeekDay() 曜日の値(日曜日を0と数える0〜6の値)
  GetHour() 「時」の値(24時間制)
  GetMinute() 「分」の値
  GetSecond() 「秒」の値

 このプログラムを実行した様子を下に示します.

         
Macintoshで実行した様子
Windowsで実行した様子

 表示が時々刻々と変化します.

[ページトップへ]


2014/08/31