[wx-dev] Template based wxEvtHandler::Connect
feature request/suggestion
Brian Vanderburg II
BrianVanderburg2 at aim.com
Wed Jul 23 15:52:28 PDT 2008
Vadim Zeitlin wrote:
> On Wed, 23 Jul 2008 14:53:41 -0400 Brian Vanderburg II <BrianVanderburg2 at aim.com> wrote:
>
> BVI> When using Connect, it just calls a target with a specific event, so why
> BVI> not make it where it can call anything by using some type of simple
> BVI> functor.
>
> This is something we'd indeed like to do. Nobody simply had time/energy
> to do this so far.
>
> Your ideas definitely seem to go in the right sense but I'm not sure if
> you already compiled/tested this or not, unexpected problems could be found
> this way.
>
> I'd also be curious if such code compiles with VC6. I don't have much hope
> but who knows, after all boost::function<> does manage to support it,
> albeit using the ugly "portable" syntax. And we need less than its full
> power here.
>
I haven't tested this at all yet, as it would require changes to what
the dynamic event table stores and that may be a pretty big change, I
don't know.
> BVI> Instead of writing:
> BVI>
> BVI> Connect(id, wxEVT_TOOL, wxCommandEventFunction(&MyFrame::OnTool))
> BVI>
> BVI> I can write:
> BVI>
> BVI> ConnectMember(id, wxEVT_TOOL, &MyFrame::OnTool);
>
> The problem is that this is unsafe. If OnTool() takes a wxPaintEvent
> instead of wxCommandEvent this is still going to compile AFAICS. If you've
> found a better way of avoiding this than specializing some template for all
> wxEVT_XXX constants with the expected type of the handler for this event
> (as I suggested it in the past) I'd really like to know about it.
>
I just responded to another post about the same, and had the Idea that
if wxEVT_PAINT was a class then
wxEVT_PAINT::EventObjectType could be a typedef to the correct event,
with a static member int GetTypeValue() that would return the true
registered type value. The event macros would simply call
type::GetTypeValue() instead of just type, and the template can then be
required to check it:
template <typename C, typename E>
void ConnectMember(int id, E type, void (*C::fn)(typename
E::EventObjectType&), C* obj)
{
}
This would require receiving an object when calling the template function:
ConnectMember(wxEVT_PAINT(), &MyClass::OnPaint, this);
A better idea is to omit the type from an argument to
ConnectFunction/ConnectMember and call it as this:
template <typename C, typename E>
void ConnectMember(int id, void (*C::fn)(typename E::EventObjectType&),
C* obj)
{
}
Then it would be connected in user code as:
ConnectMember<wxEVT_PAINT>(id, &MyClass::OnPaint);
For the default Connect to work, a wxEVT_EVENT would have to exist with
EventObjectType of wxEvent:
Connect(...)
{
ConnectMember<wxEVT_EVENT>(...)
}
This is just some testing code I've done:
#include <iostream>
class Type1Event // eg wxPaintEvent
{
public:
};
class Type1 // eg wxEVT_PAINT
{
public:
static int GetEventValue() { return 1; }
typedef Type1Event EventObjectType;
};
class Type2Event
{
public:
};
class Type2
{
public:
static int GetEventValue() { return 2; }
typedef Type2Event EventObjectType;
};
template <typename E>
void Connect(void (*fn)(typename E::EventObjectType&))
{
std::cout << "HERE I AM\n";
std::cout << "Event Type Value: " << E::GetEventValue() << "\n";
}
void fn1(Type1Event&)
{
}
void fn2(Type2Event&)
{
}
int main()
{
Connect<Type1>(fn1);
Connect<Type2>(fn2);
// Connect<Type2>(fn1); // Compiler error
return 0;
}
The Connect function would then check that the function is getting the
correct argument for the type of event. Behind the scenes it would
still extract the integer event value and store it in the event table
and the functor object. Any place that needs the literal value would
just call wxEVT_BLAH::GetTypeValue() instead of just wxEVT_BLAH.
Just some ideas.
Brian Vanderburg II
More information about the wx-dev
mailing list