Search code examples
c++eventsevent-handlingwxwidgets

What is the best way to include my own data in an event in wxWidgets?


I am trying to implement file-like structure. File and Folder names are displayed in ListBox.

I want to add additional data to ListBox entries - now it has only it's string, I want it to have a bool to differentiate between folders and files, so when I double click and OnDoubleClick(wxCommandEvent&) method which I have bound to this event is called I can access the additional data.

I know I can create custom Events or subclass existing ones but how can I customize ListBox to hold more data?


Solution

  • wxListBox derives from wxItemContainer which means that it allows each item to hold an extra piece of data. For example, you can define a client data class like this:

    class MyClientData:public wxClientData
    {
    public:
        enum ItemType
        {
            ItemTypeInvalid,
            File,
            Folder
        };
    
        MyClientData(ItemType it):m_itemType(it){}
        ItemType GetItemType() const{return m_itemType;}
    
    private:
        ItemType m_itemType;
    };
    

    You can then attach the client data to the listbox items when you append them to the control like this:

    listbox->Append("Folder 1", new MyClientData(MyClientData::Folder));
    listbox->Append("Folder 2", new MyClientData(MyClientData::Folder));
    listbox->Append("File 1", new MyClientData(MyClientData::File));
    listbox->Append("File 2", new MyClientData(MyClientData::File));
    listbox->Append("File 3", new MyClientData(MyClientData::File));
    listbox->Append("File 4", new MyClientData(MyClientData::File));
    listbox->Append("No Client Data 1");
    

    Since MyClientData is derived from wxClientData, the listbox will take ownership of the client data objects and delete them in its destructor or when the items are deleted from the control.

    You can recover the client data in the OnDoubleClick method (assuming that method is handling the wxEVT_LISTBOX_DCLICK event for your listbox) like this:

    void xxx::OnDoubleClick(wxCommandEvent& event)
    {
        int itemNo = event.GetSelection();
        wxListBox* listBox = wxDynamicCast(event.GetEventObject(), wxListBox);
        MyClientData* clientData = NULL;
    
        if ( listBox != NULL && itemNo != wxNOT_FOUND )
        {
            clientData=static_cast<MyClientData*>(listBox->GetClientObject(itemNo));
        }
    
        ... do something with clientData here ...
    }
    

    Finally, as Igor said, I'm not sure wxListBox is the best control to use here. wxListCtrl or wxDataViewListCtrl would probably look better. Those controls are a little more complicated and do not derive from wxItemContainer. However, you can still attach extra data with for example wxListCtrl::SetItemPtrData, but you'll have to clean up any dynamically created objects yourself.