2

I have to create an 2 custom events. I followed this link & made my code :--
Is there a cleaner way to register Qt custom events?

Is it the right way to create & post & pass some data(Qstring) to the customized event ?

===========================================================

Edit code as per Kuba Ober sugession :---

Mainwindow.h :--

UpdateEvent *myUpdateEvent ;
ClearEvent *myClearEvent ;

Mainwindow.c :---

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    i =0;
    myUpdateEvent = new UpdateEvent("hello");
    myClearEvent  = new ClearEvent("bye");

    QCoreApplication::postEvent(this, myUpdateEvent);
    QCoreApplication::postEvent(this, myClearEvent);


}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{

    qDebug() << "oo";
   if (UpdateEvent::is(event)) {
       UpdateEvent *tempUpdateEvent = static_cast<UpdateEvent *>(event);
       qDebug() << tempUpdateEvent->value();

   }
   else if (ClearEvent::is(event)) {
       ClearEvent *tempClearEvent = static_cast<ClearEvent *>(event);
       qDebug() << tempClearEvent->value();

   }

   return true;

}

event.h file :--

template <typename T> class StringEvent : public QEvent
{
   QString m_str;
public:
   explicit StringEvent(const QString val) : QEvent(staticType()), m_str(val)
   {
   }

   QString setvalue(QString val)
   {
       m_str = val;
   }

   QString value() const
   {
       return m_str;
   }

   static QEvent::Type staticType()
   {
      static int type = QEvent::registerEventType();
      return static_cast<QEvent::Type>(type);

   }

   static bool is(const QEvent * ev)
   {
       return ev->type() == staticType();
   }
};

class UpdateEvent : public StringEvent<UpdateEvent>
{
public:
    explicit UpdateEvent(QString val): StringEvent(val)
    {

    }

};

class ClearEvent  : public StringEvent<ClearEvent>
{
public:
    explicit ClearEvent(QString val): StringEvent(val)
    {

    }
};

why eventFilter is not triggered ? And i am not able to see debug message on postevent ?

Community
  • 1
  • 1
Katoch
  • 2,709
  • 9
  • 51
  • 84

1 Answers1

0

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 for EventMF<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)) {
      ...
   }
   ...
}
Community
  • 1
  • 1
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • thanks .. learned a lot c++ concept from this thread... last thing metafactory means class within a class ? – Katoch Oct 04 '13 at 17:32
  • @Katoch: A metafactory is a class that produces other classes for you. Here, `Update` and `Clear` are metafactories that generate the correct nested `Event` class for you, at each point of use. I've [asked another question](http://stackoverflow.com/q/19187469/1329652) to get community feedback on whether there's any simpler way of doing it. – Kuba hasn't forgotten Monica Oct 04 '13 at 17:42
  • I will suggest that our work would have also be done without using template class ... because we are not at all using template variable T inside our string event class... as shown in this example ... http://www.cprogramming.com/tutorial/templates.html .... what do you say... ? – Katoch Oct 04 '13 at 18:03
  • ok thats why in statictype() function .. return static_cast(type); .. statement typecast it to unique type T .... thanks got the full concept...!! – Katoch Oct 05 '13 at 02:08
  • @Katoch: No, the typecast is not to a unique type, it's simply because `QEvent::Type` is not an `int`, but an enum. It's a red herring. For every type `D` there is a separate `EventWrapper::staticType()`. Thus you have `EventWrapper::staticType()` and also `EventWrapper::staticType()`. They are separate functions that the compiler generates for you. – Kuba hasn't forgotten Monica Oct 05 '13 at 03:45
  • @Kuba.. Can you please edit your comment how this is working ... Update::Event update("update"); .... Clear::Event clear("clear"); .. how & to who this word "update" & "clear" will be assigned.. in what sequence constructor of EVENTMF & StringData class will be called... i am bit confused with it.. please suggest. – Katoch Oct 23 '13 at 08:16
  • @Katoch: I've done it for you. You could have of course done it yourself by adding some debug output in each of the constructors. – Kuba hasn't forgotten Monica Oct 23 '13 at 12:53