Summary:
After adapting the code in the wxwidgets Hello World tutorial into a "module" in the CppMicroServices framework, events registered using the Event Table or Bind() do not appear to fire, but events registered using Connect() do.
i.e. When I click on menu items, I don't get the pop up. If I use Connect(...) to register the event handler, the pop up does work.
Why does this happen, and how can I fix it?
Environment:
- Ubuntu 14.04
- g++ 4.9
- wxWidgets 3.0.2
- biicode 3.0
Code:
Github repository - for the full source. It doesn't build easily (ask me for compilation steps if it will help to diagnose this).
// The following are excerpts, I haven't included the namespace declarations / #includes
// === BlankDisplayService.cpp === //
// I know the constructor is "heavy", but this is just a spike
// For this issue, this is the entry point
BlankDisplayService::BlankDisplayService() {
wxApp::SetInstance( new BlankApplication() );
openWindow(0, nullptr);
}
BlankDisplayService::~BlankDisplayService() {
wxTheApp->OnExit();
wxEntryCleanup();
}
int BlankDisplayService::openWindow(int argc, char** argv) {
wxEntryStart(argc, argv);
wxTheApp->OnInit();
wxTheApp->OnRun();
return 0;
}
// === BlankApplication.cpp === //
bool BlankApplication::OnInit() {
BlankWindow *window = new BlankWindow( "Hello World", wxPoint(50, 50), wxSize(450, 340));
window->Show(true);
return true;
}
// === BlankWindow.h === //
class BlankWindow : public wxFrame {
private:
wxStaticText *st1;
wxStaticText *st2;
public:
enum Command {
ID_Hello = 1
};
BlankWindow(const wxString& title, const wxPoint& pos, const wxSize& size);
virtual ~BlankWindow();
private:
void OnMove(wxMoveEvent & event);
void OnHello(wxCommandEvent& event);
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
wxDECLARE_EVENT_TABLE();
};
// === BlankWindow.cpp === //
wxBEGIN_EVENT_TABLE(sl::desktop::demo::wx::BlankWindow, wxFrame)
EVT_MENU(ID_Hello, BlankWindow::OnHello)
EVT_MENU(wxID_EXIT, BlankWindow::OnExit)
EVT_MENU(wxID_ABOUT, BlankWindow::OnAbout)
wxEND_EVENT_TABLE()
BlankWindow::BlankWindow(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) {
wxMenu *menuFile = new wxMenu;
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H", "Help string shown in status bar for this menu item");
menuFile->AppendSeparator();
menuFile->Append(wxID_EXIT);
wxMenu *menuHelp = new wxMenu;
menuHelp->Append(wxID_ABOUT);
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append( menuFile, "&File" );
menuBar->Append( menuHelp, "&Help" );
SetMenuBar( menuBar );
CreateStatusBar();
SetStatusText( "Welcome to wxWidgets!" );
wxPanel* panel = new wxPanel(this, -1);
panel->SetSize(200, 100);
st1 = new wxStaticText(panel, -1, wxT(""), wxPoint(10, 10));
st2 = new wxStaticText(panel, -1, wxT(""), wxPoint(10, 30));
Connect(wxEVT_MOVE, wxMoveEventHandler(BlankWindow::OnMove));
Centre();
//Connect(wxEVT_MENU, wxCommandEventHandler(BlankWindow::OnHello));
}
BlankWindow::~BlankWindow() {
}
void BlankWindow::OnMove(wxMoveEvent& event) {
wxPoint size = event.GetPosition();
st1->SetLabel(wxString::Format(wxT("x: %d"), size.x ));
st2->SetLabel(wxString::Format(wxT("y: %d"), size.y ));
}
void BlankWindow::OnHello(wxCommandEvent& WXUNUSED(event)) {
wxLogMessage("Hello world from wxWidgets!");
}
void BlankWindow::OnExit(wxCommandEvent& WXUNUSED(event)) {
Close(true);
}
void BlankWindow::OnAbout(wxCommandEvent& event) {
wxMessageBox("This is a wxWidgets' Hello world sample", "About Hello World", wxOK | wxICON_INFORMATION );
}
Notes:
I'm using biicode to manage my dependencies, so the imports may not be what you're used to seeing.
I am confident that all of that runs in the main thread.
Update:
Shifting the openWindow(...) call from the constructor of BlankDisplayService into the test class caused the events declared using the event table to fire correctly. However I haven't been able to determine why - the threadIds are exactly the same whether it is called from within the test, or within the constructor:
When it doesn't work:
[MAIN] Thread Id: 140460630185856
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from SlDesktopDemoWxBundle
[ RUN ] SlDesktopDemoWxBundle.DisplaysWindow
[TEST] Thread Id: 140460630185856
[CSTR] Thread Id: 140460630185856
[OPEN] Thread Id: 140460630185856
^C
When it does work:
[CSTR] Thread Id: 139695227554368
[MAIN] Thread Id: 139695227554368
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from SlDesktopDemoWxBundle
[ RUN ] SlDesktopDemoWxBundle.DisplaysWindow
[TEST] Thread Id: 139695227554368
[OPEN] Thread Id: 139695227554368
[ OK ] SlDesktopDemoWxBundle.DisplaysWindow (3165 ms)
[----------] 1 test from SlDesktopDemoWxBundle (3165 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (3166 ms total)
[ PASSED ] 1 test.
BlankDisplayServiceis instantiated within aActivator::Load()method of your CppMicroServices module, that code is executed during static initialization of your module. If you call into external libraries, these calls might not be safe at this point in time. - Sascha