templated wxClientData wrapper for safely passing data to event handlers

12 views
Skip to first unread message

Michał Kaczorowski

unread,
Aug 26, 2026, 3:04:06 PM (13 hours ago) Aug 26
to wx-dev
Hi everyone,

I just joined this mailing list. My name is Michal, and I work as a software engineer. Apologies if this personal introduction is out of place, but hey, the guide for contributing specifically asked for it.

Anyway, I'm posting here to discuss a suggestion I have for a small addition to the project. I've been recently working on a list/listbox like container for my project and one specific aspect of it led me to writing some questionable code that I feel like it shouldn't be necessary and I think I know how it can be improved. So please, humour me for a moment.

I have a class that holds some arbitrary data and, crucially, is unaware of wxWidgets. It's purely oriented on business logic. Let's call it "Foo". When selecting an item in said list, I'd like to fire off an event (ideally wxListEvent, but wxCommandEvent works too) and pass a pointer to "Foo" that matches the item in the list or nullptr if the item in the list doesn't represent "Foo". This allows the event handler to display the content of Foo in a separate view and decouples the list from other UI elements. I know of two ways to do it. One is to pass a void* to wxCommandEvent::SetClientData(void*) and then in the event handler use static_cast to cast it back to "Foo". However this is a very brittle design, and I don't like it. The other option (as I understand it) is to create a new class that inherits from wxClientData, then pass an instance of it to wxCommandEvent::SetClientObject(wxClientData*). Which is better, but requires creating (and naming) a class in question for each type or alternatively making "Foo" inherit from wxClientData. In my case, like I said earlier, Foo is intentionally not tied to wxWidgets, so inheritance is out of the question and creating a special wrapper class works quite well, but I think it can be made better.

I'm sure I'm not the first and won't be the last person who will have this problem, which is why I'd like to propose a solution to it, in the form of a templated wrapper for wxClientData of the following form.

template <typename T> class wxClientDataWrapper : public wxClientData {
public:
    wxClientDataWrapper(T obj) : m_data(obj){}
    T m_data;
};

This can then be used to pass arbitrary data in a single function call, possibly even in a single line, like so:

wxListEvent* e = new wxListEvent(wxEVT_LIST_ITEM_SELECTED, GetId());
e->SetClientObject(new wxClientDataWrapper<Foo*>(pointer_to_foo));
wxQueueEvent(this, e);

and then retrieved in the event handler like so:

void Bar::OnSelectionChanged(wxListEvent& e) {
    Foo* f = dynamic_cast<wxClientDataWrapper<Foo*>*>(e.GetClientObject())->m_data;
}

Yes, this needs some extra care with object ownership and all, but with the magic of RTTI it allows for safely passing data around without tying it to wxWidgets too much.

I've tested this idea with MSVC and it behaves as expected. I can retrieve the m_data when the template is specialized the same way on both ends and it throws an exception if they are mismatched and I don't check them. I haven't tried it with GCC or LLVM, and I'm not sure how this will play with crossing boundaries of different binaries, so please share your wisdom with me.

Please note that m_data is of type T and not T*. I'd like for it to stay this way, on an off chance someone decides to quickly add it to the project, as it allows for passing simple things like std:vector or std:tuple or even std::shared_ptr without forcing the use of raw pointers.

In any case, I'm looking forward to hear what people here think of the idea and in the mean time I'd like to wish all of you a nice evening.

Sincerely,
Michal Kaczorowski

Vadim Zeitlin

unread,
Aug 26, 2026, 5:22:59 PM (11 hours ago) Aug 26
to wx-...@googlegroups.com
On Wed, 26 Aug 2026 11:52:19 -0700 (PDT) Michał Kaczorowski wrote:

MK> Hi everyone,
MK>
MK> I just joined this mailing list. My name is Michal, and I work as a
MK> software engineer. Apologies if this personal introduction is out of place,
MK> but hey, the guide for contributing specifically asked for it.

Hi Michal and welcome to the list!

MK> I'm sure I'm not the first and won't be the last person who will have this
MK> problem,

No, this is indeed a common problem and I did think about fixing it in the
past, but unfortunately I haven't found any solution that I really liked.
The best thing we have currently is wxEventAnyPayloadMixin, which is rather
ergonomic on its own, but using it requires either defining your own event
class or using wxThreadEvent, which already inherits from it.

But I think defining something like wxClientDataAny which would provide
member functions similar to wxEventAnyPayloadMixin, i.e. template
{Set,Get}Payload(), could be useful as then you could just associate such
client data object with your listbox item and retrieve its data in your
handler. Wouldn't this solve your problem?

MK> which is why I'd like to propose a solution to it, in the form of
MK> a templated wrapper for wxClientData of the following form.
MK>
MK> template <typename T> class wxClientDataWrapper : public wxClientData {
MK> public:
MK> wxClientDataWrapper(T obj) : m_data(obj){}
MK> T m_data;
MK> };
MK>
MK> This can then be used to pass arbitrary data in a single function call,
MK> possibly even in a single line, like so:
MK>
MK> wxListEvent* e = new wxListEvent(wxEVT_LIST_ITEM_SELECTED, GetId());
MK> e->SetClientObject(new wxClientDataWrapper<Foo*>(pointer_to_foo));
MK> wxQueueEvent(this, e);

What I don't understand is why are you sending wxEVT_LIST_ITEM_SELECTED
yourself? This is only supposed to be done by wxListBox.

MK> and then retrieved in the event handler like so:
MK>
MK> void Bar::OnSelectionChanged(wxListEvent& e) {
MK> Foo* f =
MK> dynamic_cast<wxClientDataWrapper<Foo*>*>(e.GetClientObject())->m_data;
MK> }

This is still not great because dynamic_cast<> may fail. But mostly I
don't understand where will "Foo" come originally from as, again, the
wxListEvent is generated by wxListBox which doesn't know anything about it.

Regards,
VZ

Michał Kaczorowski

unread,
Aug 26, 2026, 6:41:39 PM (9 hours ago) Aug 26
to wx-dev
VZ> defining something like wxClientDataAny which would provide
VZ> member functions similar to wxEventAnyPayloadMixin, i.e. template
VZ>  {Set,Get}Payload(), could be useful as then you could just associate such
VZ>  client data object with your listbox item and retrieve its data in your
VZ>  handler. Wouldn't this solve your problem?

Essentially yes, although I have to admit the entire wxAny and its inner workings go way over my head. I might be a bit biased, but I like my idea better.

VZ>  This is still not great because dynamic_cast<> may fail.

This is precisely what I want it to do. I should have split the dynamic_cast line properly and show the nullptr check, for the sake of demonstration, my bad. My intention with this is to cast the payload from GetClientObject(), first to the proposed templated wrapper using dynamic_cast, then check if the cast succeeded and if so do something useful with it. Personally I would intentionally skip the nullptr check to have it throw an exception should someone in the future expand the possible types and forgot to update the handler. Assertion is another great option. This is very much a case where it will not be caught until run-time, but either way I want it to fail through type system checks and not due to segmentation fault.

VZ> why are you sending wxEVT_LIST_ITEM_SELECTED
VZ> yourself? This is only supposed to be done by wxListBox.

Dully noted. I went with that specific event because, as dumb as it sounds, its name is the closest match to what I'm doing. I'm implementing an odd widget that is somewhere between a listbox and a treectrl, essentially tree of depth one, but with leaf items being more than a simple string, non collapsible tree view and with extra bells and whistles. wxListBox doesn't cut it, wxTreeCtrl brings too much functionally and not enough customization options and it all has to look and feel like the previous iteration did for the last 15 years. So I've made a class that derives from wxPanel (probably should have been wxControl, but oh well), and builds the content in wxBoxSizer with items being instantiated from one of two polymorphic classes for either the top level or leaf item. If this sounds outright unhinged then that's probably because it is; apologies. It's very much a one-off, so I'm not particularly bothered by the intricate details of reusability and generalization. What matters in this case is that the event fired is some kind of a wxCommandEvent since I need it to propagate upwards. The choice of event being sent might be questionable, but at the end of the day, an event is an event. And if you didn't want me to use wxEVT_LIST_ITEM_SELECTED "shoulda made it private :P"

VZ> But mostly I
VZ> don't understand where will "Foo" come originally from

Foo is a class that exists entirely outside of wxWidgets and UI. For illustration purposes imagine you have two classes, Manufacturer and Model. Manufacturer stores information about a car manufacturer, like Ford, Kia, Nissan, etc. while Model is for a specific car model, e.g. Mustang, Skyline, Viper. My listbox like widget gets a pointer to an array of Manufacturers each of which has its own list of Models. The actual data structure is managed somewhere else, and is not allowed to be combined with wxWidgets, i.e. no inheritance from any wxWidgets' class is allowed. Once the listbox is populated by going over that list of lists, if user clicks on any item it fires off an event, and either passes a nullptr if they clicked on a Manufacturer or a pointer to the instance of a Model if they clicked on a specific Model. In other words if you select Ford, the event will send a nullptr as payload and if you select Skyline it will pass a pointer to the instance of the Model that was used to populate that specific item in the list. I'm greatly oversimplifying the whole design, but the way it's split in code and the use of events is arguably correct. What I need it to do is send that pointer in a way that three years from now if someone adds a new class at the same level as Model and includes it in the list the code won't start randomly crashing, because the layout of two classes is nearly identical, but not quite. I want it to crash as soon as the wrong class is being dereferenced.

I know what I'm going to do in my code, but I'm writing here to share that solution in case it benefits others and I'm happy to implement it and open a PR if we can workout a satisfactory design. It feels worthwhile to me, since like you've said "(...) this is indeed a common problem (...)".

Regards,
Michal Kaczorowski

Vadim Zeitlin

unread,
Aug 26, 2026, 7:16:27 PM (9 hours ago) Aug 26
to wx-...@googlegroups.com
On Wed, 26 Aug 2026 15:41:39 -0700 (PDT) Michał Kaczorowski wrote:

MK> VZ> But mostly I don't understand where will "Foo" come originally from
MK>
MK> Foo is a class that exists entirely outside of wxWidgets and UI.

Yes, I understand this. But the question then becomes: is your GUI control
specific to your Foo? If it is, then you could just as well create your
wxFooEvent class (maybe deriving from some existing class) and add all the
functions you need to get Foo from it. If it isn't, which is a more
interesting use case, then it can't know about Foo.

What might work here would be some wxListCtrl<T> which would be a
wxListBox containing items of type T and could be instantiated with T=Foo
(or anything else).

But I don't understand what do you propose to do to make the code sending
the event -- which must be inside a class that doesn't know about Foo,
because otherwise it's too simple to be interesting -- capable of
generating events carrying Foo. To be honest, I don't think is possible.

Regards,
VZ
Reply all
Reply to author
Forward
0 new messages