Page 1 of 1

Unresolved external symbol with wxDECLARE_EVENT

Posted: Wed Jul 31, 2019 9:08 am
by sw
Hi all,

I have searched through the forums to see if anyone has experienced this issue, but I have not found anything.

I was following the wiki page for creating custom events https://wiki.wxwidgets.org/Custom_Event ... -_Method_4

I am trying to post a event from a dialog to the main (parent) frame. In the dialog header file I have added the macro to declare the event like so:

Code: Select all

wxDECLARE_EVENT(TASK_INSERTED, wxCommandEvent);
This line is placed after all includes and before the class declaration. And in the source file I define the event:

Code: Select all

wxDEFINE_EVENT(TASK_INSERTED, wxCommandEvent);
My main issue is that when I compile the code, the linker complains about a "unresolved external symbol". This is the full error:
LNK2001 unresolved external symbol "class wxEventTypeTag<class wxCommandEvent> const TASK_INSERTED" (?TASK_INSERTED@@3V?$wxEventTypeTag@VwxCommandEvent@@@@B)
This error is coming from the frame obj file.

I don't think I am missing a include as I am including wx/wx.h in both the frame and dialog header files. I am using wxWidgets 3.1.2-1 on Windows 10 with VS2019

Re: Unresolved external symbol with wxDECLARE_EVENT

Posted: Wed Jul 31, 2019 11:37 am
by doublemax
That looks ok to me. Can you show how you use the new event?

https://docs.wxwidgets.org/trunk/overvi ... nts_custom

Re: Unresolved external symbol with wxDECLARE_EVENT

Posted: Wed Jul 31, 2019 11:38 am
by PB
The code you posted should work, the issue must be elswhere.

FWIW, this works as expected

MyDialog.h

Code: Select all

#pragma once

#include <wx/wx.h>

wxDECLARE_EVENT(TASK_INSERTED, wxCommandEvent);

class MyDialog : public wxDialog
{
public:
    MyDialog(wxWindow* parent);
protected: 
    void OnAddTask(wxCommandEvent&);
};
MyDialog.cpp

Code: Select all

#include "MyDialog.h"

MyDialog::MyDialog(wxWindow* parent) 
    : wxDialog(parent, wxID_ANY, "Add Task Dialog")
{                                                                      
    wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
        
    wxButton* button = new wxButton(this, wxID_ANY, "Add Task");
    button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyDialog::OnAddTask, this);
    mainSizer->Add(button, wxSizerFlags().Expand().DoubleBorder());

    mainSizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Expand().DoubleBorder());
                        
    SetSizerAndFit(mainSizer);
}	

void MyDialog::OnAddTask(wxCommandEvent&)
{
    wxCommandEvent event(TASK_INSERTED, GetId());
    
    event.SetEventObject(this);    
    GetParent()->ProcessWindowEvent(event);
}
MyFrame.cpp

Code: Select all

#include <wx/wx.h>

#include "MyDialog.h"

wxDEFINE_EVENT(TASK_INSERTED, wxCommandEvent);

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame(nullptr, wxID_ANY, "Test", wxDefaultPosition, wxSize(800, 600))          
    {  
        wxPanel* mainPanel = new wxPanel(this);        
        wxBoxSizer* mainPanelSizer = new wxBoxSizer(wxVERTICAL);
        
        wxButton* button = new wxButton(mainPanel, wxID_ANY, "Show Dialog...");
        button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnShowDialog, this);
        mainPanelSizer->Add(button, wxSizerFlags().Expand().DoubleBorder());
        
        wxTextCtrl* logCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 
            wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);     
        wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));                                         
        mainPanelSizer->Add(logCtrl, wxSizerFlags().Expand().DoubleBorder().Proportion(5));

        mainPanel->SetSizer(mainPanelSizer);

        Bind(TASK_INSERTED, &MyFrame::OnAddTask, this);
    }   
protected:            

    void OnShowDialog(wxCommandEvent&)
    {   
        MyDialog dlg(this);

        dlg.ShowModal();
    }

    void OnAddTask(wxCommandEvent&)
    {
        wxLogMessage("Task added.");
    }
};

class MyApp : public wxApp
{
public:   
    bool OnInit() override
    {
        (new MyFrame)->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);;
Not sure whether something like this, i.e., passing the event from the modal dialog, is a good idea....

Re: Unresolved external symbol with wxDECLARE_EVENT

Posted: Wed Jul 31, 2019 11:53 am
by sw
In the dialog:

Code: Select all

wxCommandEvent taskInsertedEvent(TASK_INSERTED);
wxPostEvent(pParent, taskInsertedEvent);
where pParent is a pointer to the frame class.

In the frame:

Code: Select all

wxBEGIN_EVENT_TABLE(MainFrame, wxFrame)
...
EVT_COMMAND(wxID_ANY, TASK_INSERTED, MainFrame::OnTaskInserted)
...
wxEND_EVENT_TABLE()

void MainFrame::OnTaskInserted(wxCommandEvent& event)
{
    pListCtrl->DeleteAllItems();
    RefreshItems();
}

Re: Unresolved external symbol with wxDECLARE_EVENT

Posted: Wed Jul 31, 2019 12:36 pm
by PB
Do you have wxDEFINE... above the message table definition?

Does the issue persist when you use Bind() instead of the static event table or just comment out the line in the message table in frame source file?

Re: Unresolved external symbol with wxDECLARE_EVENT

Posted: Wed Jul 31, 2019 1:17 pm
by sw
I'm so embarrassed, but I figured it out. I'm using namespaces in my application and I put the wxDEFINE_EVENT inside the namespace of the dialog source file. The frame is also in a namespace, but in a different one hence why the linker was struggling to find the event. Moving it out of the namespace has resolved the linker problem.

Thank you PB, your comment set me on the right path. And thank you doublemax too.