create & post the customized Qevent
Asked Answered
F

1

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 ?

Funds answered 2/10, 2013 at 10:28 Comment(0)
L
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)) {
      ...
   }
   ...
}
Landlord answered 3/10, 2013 at 16:22 Comment(7)
thanks .. learned a lot c++ concept from this thread... last thing metafactory means class within a class ?Funds
@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 to get community feedback on whether there's any simpler way of doing it.Identity
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 ... cprogramming.com/tutorial/templates.html .... what do you say... ?Funds
ok thats why in statictype() function .. return static_cast<QEvent::Type>(type); .. statement typecast it to unique type T .... thanks got the full concept...!!Funds
@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<D>::staticType(). Thus you have EventWrapper<Update::EventFwd>::staticType() and also EventWrapper<Clear::EventFwd>::staticType(). They are separate functions that the compiler generates for you.Identity
@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.Funds
@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.Identity

© 2022 - 2024 — McMap. All rights reserved.