I can only comment on the code smell of your event implementation, since it is at this point unclear why would you need to send events to an edit control within a window. The latter is bad design.
Your Event class is needlessly complicated. You should be setting up all values inside the event during construction, and they should be accessible through read-only accessors afterwards. The extra event type seems to be an unnecessary gimmick as well.
Here's how I'd do it, using a metafactory pattern (a name I just coined, perhaps there's a better/existing name for it?). This solves the need for explicit derived class constructor injection that'd be otherwise needed.
I've split up the metafactory into small constituent classes for ease of understanding.
// A type-identifier-generating wrapper for events
template <typename D> class EventWrapper : public QEvent {
public:
EventWrapper() : QEvent(staticType()) {}
static QEvent::Type staticType() {
static QEvent::Type type = static_cast<QEvent::Type>(registerEventType());
return type;
}
static bool is(const QEvent * ev) { return ev->type() == staticType(); }
static D* cast(QEvent * ev) { return is(ev) ? static_cast<D*>(ev) : 0; }
};
// The generic event metafactory for C++98 (doesn't need C++11)
template <typename D, template <typename> class Carrier> class EventMF {
class EventFwd;
class Final;
class FinalWrapper : public EventWrapper<EventFwd>, public virtual Final {};
public:
// EventFwd is a class derived from Event. The EventWrapper's cast()
// will cast to a covariant return type - the derived class. That's OK.
typedef Carrier<FinalWrapper> Event;
private:
class EventFwd : public Event {};
class Final {
friend class FinalWrapper;
friend class Carrier<FinalWrapper>;
private:
Final() {}
Final(const Final &) {}
};
};
// A string carrier
template <typename B> class StringData : public B {
QString m_str;
public:
explicit StringData(const QString & str) : m_str(str) {}
QString value() const { return m_str; }
};
// A string event metafactory
template <typename D> class StringEventMF : public EventMF<D, StringData> {};
class Update : public EventMF<Update, StringData> {}; // using generic metafactory
class Clear : public StringEventMF<Clear> {}; // using specific metafactory
#if 0
// This should fail at compile time as such derivation would produce classes with
// duplicate event types. That's what the Final class was for in the matafactory.
class Error : public Update::Event { Error() : Update::Event("") {} };
#endif
int main(int, char**)
{
// Test that it works as expected.
Update::Event update("update");
Clear::Event clear("clear");
Q_ASSERT(Update::Event::staticType() != Clear::Event::staticType());
Q_ASSERT(Update::Event::staticType() == Update::Event::cast(&update)->staticType());
qDebug() << Update::Event::cast(&update)->value();
Q_ASSERT(Update::Event::cast(&clear) == 0);
qDebug() << Clear::Event::cast(&clear)->value();
Q_ASSERT(Clear::Event::cast(&update) == 0);
}
The Metafactory::Event
classes are the custom event classes that derive from QEvent
.
The class hierarchy for Update::Event looks as follows (going from the least derived to most derived class):
EventWrapper<EventMF<...>::EventFwd>
,EventMF<...>::Final
(multiple inheritance)EventMF<Update, StringData<Update>>::FinalWrapper
StringData<Update> = EventMF<Update, StringData<Update>>::Event
with
EventMF<...>
being shorthand forEventMF<Update, StringData<Update>
.
The line Update::Event update("update")
constructs a custom string-carrying event instance, with the constructors called from the last to the first in the list above.
Since EventMF<...>
is a metafactory that works at time of compilation only, there is absolutely no need for its instance to exist at runtime. Thus EventMF<...>::EventMF
constructor is never called. You can enforce this invariant by deleting the constructor (declaring it private for C++98).
The use within an event handler would look like:
void MainWindow::customEvent(QEvent *event)
{
...
if (Update::Event::is(event)) {
qDebug() << Update::Event::cast(event)->value();
...
}
else if (Clear::Event::is(event)) {
...
}
...
}