wxEvtHandler::Connect() and user data from a C programmer's point of view

294 views
Skip to first unread message

Andreas Falkenhahn

unread,
Jul 20, 2015, 3:01:59 PM7/20/15
to wx-u...@googlegroups.com
How can I pass a pointer as user data to a wxWidgets event callback function?
For example, I want to pass the pointer "myuserdata" to a button click
callback. I see that wxEvtHandler::Connect() accepts a "userData" parameter
but, alas, it has to be of type "wxObject" so I guess wxWidgets does
some major OOP wizardry here. But I don't actually need that... I just
want to pass a pure and simple pointer to the event callback, nothing
fancy, really. Why does everything have to be so complicated in C++ ;-)

So I guess I'd somehow have to wrap this pointer in a wxObject compatible
class and pass an instance of this class to Connect()? Unfortunately, this
is quite a major challenge for me because I'm a total C++ noob and try to
avoid it as much as possible so it'd be helpful if somebody could point me
to some example code that does something similar to what I'm trying to
achieve...

Thanks!

--
Best regards,
Andreas Falkenhahn mailto:and...@falkenhahn.com

Igor Korot

unread,
Jul 20, 2015, 3:04:01 PM7/20/15
to wx-u...@googlegroups.com
Hi, Andreas,
I presume you already look at the event sample?

Thank you.

>
> Thanks!
>
> --
> Best regards,
> Andreas Falkenhahn mailto:and...@falkenhahn.com
>
> --
> Please read http://www.wxwidgets.org/support/mlhowto.htm before posting.
>
> To unsubscribe, send email to wx-users+u...@googlegroups.com
> or visit http://groups.google.com/group/wx-users

Andreas Falkenhahn

unread,
Jul 20, 2015, 3:10:46 PM7/20/15
to Igor Korot
Hi Igor,

On 20.07.2015 at 21:03 Igor Korot wrote:

> Hi, Andreas,

> On Mon, Jul 20, 2015 at 3:03 PM, Andreas Falkenhahn
> <and...@falkenhahn.com> wrote:
>> How can I pass a pointer as user data to a wxWidgets event callback function?
>> For example, I want to pass the pointer "myuserdata" to a button click
>> callback. I see that wxEvtHandler::Connect() accepts a "userData" parameter
>> but, alas, it has to be of type "wxObject" so I guess wxWidgets does
>> some major OOP wizardry here. But I don't actually need that... I just
>> want to pass a pure and simple pointer to the event callback, nothing
>> fancy, really. Why does everything have to be so complicated in C++ ;-)

>> So I guess I'd somehow have to wrap this pointer in a wxObject compatible
>> class and pass an instance of this class to Connect()? Unfortunately, this
>> is quite a major challenge for me because I'm a total C++ noob and try to
>> avoid it as much as possible so it'd be helpful if somebody could point me
>> to some example code that does something similar to what I'm trying to
>> achieve...

> I presume you already look at the event sample?

Yes, but I don't see where this uses the "userData" parameter. I looked
at all instances of Connect() in samples/event/event.cpp but AFAICS it
never uses the userData parameter or am I missing something here?

Vadim Zeitlin

unread,
Jul 20, 2015, 8:32:04 PM7/20/15
to wx-u...@googlegroups.com
On Mon, 20 Jul 2015 21:03:02 +0200 Andreas Falkenhahn wrote:

AF> How can I pass a pointer as user data to a wxWidgets event callback function?
AF> For example, I want to pass the pointer "myuserdata" to a button click
AF> callback. I see that wxEvtHandler::Connect() accepts a "userData" parameter
AF> but, alas, it has to be of type "wxObject" so I guess wxWidgets does
AF> some major OOP wizardry here. But I don't actually need that... I just
AF> want to pass a pure and simple pointer to the event callback, nothing
AF> fancy, really.

You will have to wrap your pointer into a heap-allocated object of a
wxObject-derived class, there is no way around it. It's trivial to do, of
course, but does add some overhead due to the use of dynamic allocation. To
sweeten the pill, I can point you to Bind() which allows you to specify a
pure and simple function instead of an object method as Connect() does.

Regards,
VZ

--
TT-Solutions: wxWidgets consultancy and technical support
http://www.tt-solutions.com/

Andreas Falkenhahn

unread,
Jul 21, 2015, 3:27:57 PM7/21/15
to Vadim Zeitlin
On 21.07.2015 at 02:32 Vadim Zeitlin wrote:

> On Mon, 20 Jul 2015 21:03:02 +0200 Andreas Falkenhahn wrote:

AF>> How can I pass a pointer as user data to a wxWidgets event callback function?
AF>> For example, I want to pass the pointer "myuserdata" to a button click
AF>> callback. I see that wxEvtHandler::Connect() accepts a "userData" parameter
AF>> but, alas, it has to be of type "wxObject" so I guess wxWidgets does
AF>> some major OOP wizardry here. But I don't actually need that... I just
AF>> want to pass a pure and simple pointer to the event callback, nothing
AF>> fancy, really.

> You will have to wrap your pointer into a heap-allocated object of a
> wxObject-derived class, there is no way around it. It's trivial to do, of
> course, but does add some overhead due to the use of dynamic allocation. To
> sweeten the pill, I can point you to Bind() which allows you to specify a
> pure and simple function instead of an object method as Connect() does.

For me it's not really trivial since I'm a C++ noob so I'd be glad if
someone could check the following code. It's working fine but I'm not
sure whether I need an abstract or dynamic class because as a C++ noob
I don't really understand the difference between the two and the wxWidgets
macro magic doesn't make things easier for beginners. So this is what
I came up with:

class wxMyUserData: public wxObject
{
wxDECLARE_ABSTRACT_CLASS(wxMyUserData);
public: void *data;
};

wxIMPLEMENT_ABSTRACT_CLASS(wxMyUserData, wxObject);

And then to connect the event handler:

wxMyUserData *ud = new wxMyUserData;
ud->data = ...;
mybutton->Bind(wxEVT_COMMAND_BUTTON_CLICKED, mycallback, wxID_ANY, wxID_ANY, ud)

As I said, it's working fine but I'd be more relaxed if somebody could
confirm that the code is indeed alright.

Igor Korot

unread,
Jul 21, 2015, 3:35:18 PM7/21/15
to wx-u...@googlegroups.com
Andreas,
Did you look at the Bind() function like Vadim proposed?
It is much easier and less error-prone.

Thank you.

>
> --
> Best regards,
> Andreas Falkenhahn mailto:and...@falkenhahn.com
>

Andreas Falkenhahn

unread,
Jul 21, 2015, 3:37:42 PM7/21/15
to Igor Korot
Huh? Did you look at my example code above? :-)

Igor Korot

unread,
Jul 21, 2015, 3:40:05 PM7/21/15
to wx-u...@googlegroups.com
Andreas,

On Tue, Jul 21, 2015 at 3:38 PM, Andreas Falkenhahn
Please re-read what Vadim said.

In short: if you use Bind() you can simply pass you pointer in and
don't have to use
any magic.

But if you code already works - it works. ;-)

Thank you.

>
> --
> Best regards,
> Andreas Falkenhahn mailto:and...@falkenhahn.com
>

Andreas Falkenhahn

unread,
Jul 21, 2015, 3:47:48 PM7/21/15
to Igor Korot
On 21.07.2015 at 21:40 Igor Korot wrote:

> Please re-read what Vadim said.

> In short: if you use Bind() you can simply pass you pointer in and
> don't have to use
> any magic.

I don't see where Bind() should take a user data pointer directly. The
user data in Bind() is of type wxObject as it is in Connect(), so I have
to derive a class from wxObject for Bind() as well. AFAICS the only difference
is that Bind() takes a normal function pointer for the callback
whereas Connect() needs a wxObjectEventFunction.

> But if you code already works - it works. ;-)

Ah, but that's not what I wanted to hear :-) I don't really know
anything about C++ so I'd like to have somebody confirm that the
code is alright because the fact that it works doesn't imply that
it's correct code...

Igor Korot

unread,
Jul 21, 2015, 4:02:27 PM7/21/15
to wx-u...@googlegroups.com
Andreas,
Who is deleting the pointer?
Does MSVC reports any memory leaks?

Thank you.

>
> --
> Best regards,
> Andreas Falkenhahn mailto:and...@falkenhahn.com
>

Andreas Falkenhahn

unread,
Jul 21, 2015, 4:06:51 PM7/21/15
to Igor Korot
On 21.07.2015 at 22:02 Igor Korot wrote:

> Andreas,

> On Tue, Jul 21, 2015 at 3:48 PM, Andreas Falkenhahn
> <and...@falkenhahn.com> wrote:
>> On 21.07.2015 at 21:40 Igor Korot wrote:

>>> Please re-read what Vadim said.

>>> In short: if you use Bind() you can simply pass you pointer in and
>>> don't have to use
>>> any magic.

>> I don't see where Bind() should take a user data pointer directly. The
>> user data in Bind() is of type wxObject as it is in Connect(), so I have
>> to derive a class from wxObject for Bind() as well. AFAICS the only difference
>> is that Bind() takes a normal function pointer for the callback
>> whereas Connect() needs a wxObjectEventFunction.

>>> But if you code already works - it works. ;-)

>> Ah, but that's not what I wanted to hear :-) I don't really know
>> anything about C++ so I'd like to have somebody confirm that the
>> code is alright because the fact that it works doesn't imply that
>> it's correct code...

> Who is deleting the pointer?
> Does MSVC reports any memory leaks?

From wxWidgets doc:

"wxWidgets will take ownership of this pointer, i.e. it will be destroyed when the
event handler is disconnected or at the program termination. This pointer can be
retrieved using wxEvent::GetEventUserData() later."

http://docs.wxwidgets.org/trunk/classwx_evt_handler.html#a0f30c8fa5583b4a5f661897d63de3b62

Eric Jensen

unread,
Jul 21, 2015, 4:20:19 PM7/21/15
to Andreas Falkenhahn
Hello Andreas,

Tuesday, July 21, 2015, 9:29:02 PM, you wrote:

AF> macro magic doesn't make things easier for beginners. So this is what
AF> I came up with:

AF> class wxMyUserData: public wxObject
AF> {
AF> wxDECLARE_ABSTRACT_CLASS(wxMyUserData);
AF> public: void *data;
AF> };

AF> wxIMPLEMENT_ABSTRACT_CLASS(wxMyUserData, wxObject);

AF> And then to connect the event handler:

AF> wxMyUserData *ud = new wxMyUserData;
AF> ud->data = ...;
AF> mybutton->Bind(wxEVT_COMMAND_BUTTON_CLICKED, mycallback, wxID_ANY, wxID_ANY, ud)

AF> As I said, it's working fine but I'd be more relaxed if somebody could
AF> confirm that the code is indeed alright.

It would be interesting to hear about the "bigger picture" of what
you're trying to implement. In 10 years of wxWidgets use i never
needed what you're trying to do, so i'm pretty sure there is another
way to do it.

wxWidgets is a C++ library after all and if you fight "against the
system" all the time, you might not enjoy it very much ;)

In an event handler you have event.GetId() which gives you the id of
the control. And with event.GetEventObject() you get the control that
created the event. E.g. for a wxButton event it would return a pointer
to the button. These things are usually enough to react accordingly in
the event handler.

Eric


--

Andreas Falkenhahn

unread,
Jul 21, 2015, 4:43:33 PM7/21/15
to Eric Jensen
On 21.07.2015 at 22:19 Eric Jensen wrote:

> Hello Andreas,

> Tuesday, July 21, 2015, 9:29:02 PM, you wrote:

AF>> macro magic doesn't make things easier for beginners. So this is what
AF>> I came up with:

AF>> class wxMyUserData: public wxObject
AF>> {
AF>> wxDECLARE_ABSTRACT_CLASS(wxMyUserData);
AF>> public: void *data;
AF>> };

AF>> wxIMPLEMENT_ABSTRACT_CLASS(wxMyUserData, wxObject);

AF>> And then to connect the event handler:

AF>> wxMyUserData *ud = new wxMyUserData;
AF>> ud->data = ...;
AF>> mybutton->Bind(wxEVT_COMMAND_BUTTON_CLICKED, mycallback, wxID_ANY, wxID_ANY, ud)

AF>> As I said, it's working fine but I'd be more relaxed if somebody could
AF>> confirm that the code is indeed alright.

> It would be interesting to hear about the "bigger picture" of what
> you're trying to implement.

As I said, I'm writing a wxWidgets backend for a cross-platform GUI API
which is completely in C. It's all rather abstract stuff and of course
not your typical wxWidgets application. My aim is not to write beautiful
wxWidgets code but just to make things fit using as little code as possible.

>
> In 10 years of wxWidgets use i never
> needed what you're trying to do, so i'm pretty sure there is another
> way to do it.

Sorry, but that's not the point here :) I don't want to discuss alternatives
but I just want to pass an arbitrary pointer to an event callback.
I have 15+ years experience in C so I generally know very well what
I'm doing. I just need a little help with C++ and wxWidgets related
stuff.

> wxWidgets is a C++ library after all and if you fight "against the
> system" all the time, you might not enjoy it very much ;)

> In an event handler you have event.GetId() which gives you the id of
> the control. And with event.GetEventObject() you get the control that
> created the event. E.g. for a wxButton event it would return a pointer
> to the button. These things are usually enough to react accordingly in
> the event handler.

Not in my case. I absolutely need to be able to pass an arbitrary pointer
to the callback.

Please let's not turn this into something different than it is: All I
was asking for was for an experienced C++ programmer to look over my
5 lines of code and say whether it's correct or not. Is that really
so difficult? :-) It's already been like around 10 mails now but they're
all rather unrelated. I really just want somebody who knows something
about wxWidgets and C++ to confirm that the code in my first mail
is correct or not. Nothing else, thanks :-)

Eric Jensen

unread,
Jul 21, 2015, 5:07:32 PM7/21/15
to Andreas Falkenhahn
Hello Andreas,

Tuesday, July 21, 2015, 10:44:38 PM, you wrote:

AF> Please let's not turn this into something different than it is: All I
AF> was asking for was for an experienced C++ programmer to look over my
AF> 5 lines of code and say whether it's correct or not. Is that really
AF> so difficult? :-) It's already been like around 10 mails now but they're
AF> all rather unrelated. I really just want somebody who knows something
AF> about wxWidgets and C++ to confirm that the code in my first mail
AF> is correct or not. Nothing else, thanks :-)

Yes, looks ok to me.

Eric.

Igor Korot

unread,
Jul 21, 2015, 5:11:48 PM7/21/15
to wx-u...@googlegroups.com
Andreas,
We all understand that.
What Eric is trying to say is that you might mnot need it at all, because of
the language difference.

You can get from point A to point B in many different ways, and there is no
right or wrong way. You still get to point B. ;-)

All we are saying is that there might be an easier way to achieve what you
want in the first place. With the less code and it will be more efficient.

But you code appears to be correct, if there is no leakage reported and there is
no crash produced during the runtime.

Now is you program MT? Is your library? Are both of them MT-safe?

Thank you.

>
> --
> Best regards,
> Andreas Falkenhahn mailto:and...@falkenhahn.com
>

Vadim Zeitlin

unread,
Jul 21, 2015, 5:47:58 PM7/21/15
to wx-u...@googlegroups.com
On Tue, 21 Jul 2015 21:29:02 +0200 Andreas Falkenhahn wrote:

AF> For me it's not really trivial since I'm a C++ noob so I'd be glad if
AF> someone could check the following code. It's working fine but I'm not
AF> sure whether I need an abstract or dynamic class because as a C++ noob
AF> I don't really understand the difference between the two

The RTTI macros don't really have to do anything with C++, they're
wxWidgets-specific and you only need to use them if you want to be able to
get the information about the object name during run-time. You don't here,
so you don't need any of them at all.

AF> and the wxWidgets macro magic doesn't make things easier for beginners.

No, but, again, luckily you can just ignore it.

AF> So this is what I came up with:
AF>
AF> class wxMyUserData: public wxObject
AF> {
AF> wxDECLARE_ABSTRACT_CLASS(wxMyUserData);
AF> public: void *data;
AF> };
AF>
AF> wxIMPLEMENT_ABSTRACT_CLASS(wxMyUserData, wxObject);

The above works but you can also replace it with just

struct wxMyUserData : wxObject { void* data; };
Reply all
Reply to author
Forward
0 new messages