スポンサーリンク
wxWidgetsはメッセージループを隠蔽している。これを加工する。
wxGUIEventLoopを継承して、必要な機能のみ実装する。
#ifndef WX_PRECOMP #include <wx/wx.h> #endif #include <wx/gdicmn.h> // wxPointに必要 #include <wx/frame.h> // wxFrameに必要 #include <wx/evtloop.h> ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// #include <string> class MyCustomEventLoop : public wxGUIEventLoop { public: MyCustomEventLoop() = default; virtual ~MyCustomEventLoop() = default; protected:
// Yieldが必要な場合 virtual void DoYieldFor(long eventsToProcess) override { // デフォルトの実装 wxGUIEventLoop::DoYieldFor(eventsToProcess); }
// メッセージループの各イテレーション開始時に呼ばれるフック virtual void OnNextIteration() override { ////////////////////////////////// static int counter = 0; counter++; char ss[64]; snprintf(ss, sizeof(ss), "OnNextIteration called: %d", counter); wxLogDebug(ss); ////////////////////////////////// // デフォルトの実装 wxGUIEventLoop::OnNextIteration(); }
////////////////////////////////////////////// // メッセージを処理する bool Dispatch() override { MSG msg;// メッセージループの処理はOS依存 if (!::GetMessage(&msg, NULL, 0, 0)) return false; // WM_QUIT if (msg.message == WM_LBUTTONDOWN)// 処理例:WM_LBUTTONDOWNを無効化 { wxLogDebug("Ignored in custom Dispatch"); // WM_LBUTTONDOWN このメッセージを処理しないためにここでtrueを返す return true; } ProcessMessage(&msg); return true; } //////////////////////////////////////////////
// イベント処理のメインループ // *メッセージループ中に何かしたいだけなら、OnNextIteration() をオーバーライドするだけでよい // *メッセージを横取りするような用途では、Dispatch() をオーバーライドするだけでよい // より細かい制御が必要なら DoRun() をオーバーライドすることもできる #define IF_YOU_NEED_DORUN #if defined( IF_YOU_NEED_DORUN ) virtual int DoRun() override { for (;;) { // 1) ループ開始フック OnNextIteration(); // 2) キュー内の全イベントを処理 while (!m_shouldExit && Pending()) { // Dispatch() が false を返したらループ終了 if (!Dispatch()) break; } if (m_shouldExit) break; // 3) アイドル処理:戻り値 true なら更にアイドルイベントを送り続ける if (ProcessIdle()) { continue; } // 4) 何もやることがなければ少し待機 wxThread::Sleep(10); } // 返り値は Exit() でセットされたコード return m_exitcode; } #endif // IF_YOU_NEED
}; class MyFrame : public wxFrame { public: MyFrame() : wxFrame(nullptr, wxID_ANY, "メッセージループ") { Bind(wxEVT_CLOSE_WINDOW, &MyFrame::OnClose, this); // クリックイベント Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent& event) { wxLogMessage("Left mouse button clicked at (%d, %d)", event.GetX(), event.GetY()); }); } private: void OnClose(wxCloseEvent& evt) {
if (wxEventLoopBase::GetActive()) wxEventLoopBase::GetActive()->Exit();// プログラム終了
evt.Skip(); // フレーム自体も閉じる } }; class MyApp : public wxApp { public: bool OnInit() override { auto frame = new MyFrame(); frame->Show(); return true; } int OnRun() override { // wxGUIEventLoop を使って自前ループを構築 MyCustomEventLoop* loop = new MyCustomEventLoop; wxEventLoopBase::SetActive(loop); // アクティブなループとして登録 int retval = loop->Run(); // ここでメッセージループ開始 delete loop; // ループ終了後に解放 return retval; } }; // WinMainをマクロで定義 wxIMPLEMENT_APP(MyApp);