wxTimer not calling callback after binding with Bind()

Viewed 175

I'd like to use wxTimer in my application, but I don't want to use the preprocessor macros to bind the events. Instead I want to use Bind() during the CTOR call to bind the events to my ui elements.
After binding my timer, it doesn't start or it doesn't call the event handler. According to this it ought to work like I want to. I also do not want to use Connect(). Binding a button in the same way works just fine. Here is a minimal example:

minimum example:

#include <wx/wx.h>
#include <iostream>

class MainFrame : public wxFrame
{
private:
    const int DELTA_TIME = 100; // time between timer events (in ms)
private:
    wxTimer* timer = nullptr;
    void OnTimer(wxTimerEvent& evt);
    void OnButtonClick(wxCommandEvent& evt);
public:
    MainFrame();
    virtual ~MainFrame();
};

void MainFrame::OnTimer(wxTimerEvent& evt)
{
    std::cout << "Timer Event!" << std::endl; // never happens
}

void MainFrame::OnButtonClick(wxCommandEvent& evt)
{
    std::cout << "Button Event!" << std::endl; // works just fine
}

MainFrame::MainFrame()
    : wxFrame(nullptr, wxID_ANY, "Test", wxPoint(0, 0), wxSize(600, 400))
{
    timer = new wxTimer(this, wxID_ANY);
    timer->Bind(
        wxEVT_TIMER,                    // evt type
        &MainFrame::OnTimer,            // callback
        this,                           // parent
        timer->GetId()                  // id
    );
    timer->Start(DELTA_TIME, wxTIMER_CONTINUOUS);

    wxButton* testBtn = new wxButton(this, wxID_ANY, "Test", wxPoint(20, 20));
    testBtn->Bind(wxEVT_BUTTON, &MainFrame::OnButtonClick, this);
}

MainFrame::~MainFrame()
{
    if (timer->IsRunning())
    {
        timer->Stop();
    }
}

// application class
class Main : public wxApp
{
public:
    virtual bool OnInit();
};

IMPLEMENT_APP(Main)

bool Main::OnInit()
{
    MainFrame* mainFrame = new MainFrame();
    SetTopWindow(mainFrame);
    mainFrame->Show();
    return true;
}
1 Answers

You should change

timer->Bind(...

to just

Bind(...

The line timer = new wxTimer(this, wxID_ANY); sets the main frame to be the owner of the timer, so that is the item notified when the timer is fired. However the line timer->Bind(... sets up the timer to process the timer events. But the events aren't sent to the timer, they're sent to the main frame. So it is necessary to set the main frame to be the event handler, which is what the change given above does.

Related