スポンサーリンク

wxWidgetsのメッセージループを上書きする

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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: