The application uses events (inherited from QEvent ). Each event, as it should be, has a strictly defined type - an integer between QEvent::User and QEvent::MaxUser , obtained through the static function QEvent::registerEventType() .

Event types are easily identified in the receiver object method:

 void MyClass::customEvent(QEvent *event) { if(event->type() == MyEventOne::eventType()) { MyEventOne *event1 = static_cast<MyEventOne*>(event); ... } else if(event->type() == MyEventTwo::eventType()) { MyEventTwo *event2 = static_cast<MyEventTwo*>(event); ... } else ... } 

However, problems begin as soon as an event comes from a dynamically loaded plug-in. The numeric values ​​of the types of the same class are different.

I tried to register events in two ways.

Method one

File myeventone.h :

 #include <QtCore/QEvent> class MyEventOne : public QEvent { public: static const QEvent::Type &_event_type; explicit MyEventOne(); }; 

File myeventone.cpp :

 #include "myeventone.h" const QEvent::Type &MyEventOne::_event_type = static_cast<QEvent::Type>(QEvent::registerEventType()); MyEventOne::MyEventOne() : QEvent(_event_type) {} 

Second way

File myeventone.h :

 #include <QtCore/QEvent> class MyEventOne : public QEvent { public: static QEvent::Type eventType(); explicit MyEventOne(); }; 

File myeventone.cpp :

 #include <QtCore/QGlobalStatic> #include "myeventone.h" Q_GLOBAL_STATIC_WITH_ARGS(int, _g_event_type, (QEvent::registerEventType())) QEvent::Type MyEventOne::eventType() { return static_cast<QEvent::Type>(*_g_event_type); } MyEventOne::MyEventOne(): QEvent(MyEventOne::eventType()) {} 

In both cases, if I use the plugin and send an event object from it, I get a different numeric value of the event type. At the same time, the files of the MyEventOne class are the MyEventOne in the plugin and directly in the main part of the application.

I know that the QEvent::registerEventType() function has an hint argument that can act as a hint when generating a numeric value for an event type, but in this case depresses the need to define such hints (many event types) somehow globally and preferably a single list.

How can you solve this problem and if you cannot do without the above-mentioned hints, then how to use them correctly?

Addition

Made a helper static function that by name assigns a constant value to a specific type of event.

 int EventHelper::registerEventType(const QString &class_name) { if(class_name == QLatin1String("MyEventOne")) return QEvent::registerEventType(QEvent::User+1000); else if(class_name == QLatin1String("MyEventTwo")) return QEvent::registerEventType(QEvent::User+1001); return QEvent::registerEventType(); } 

As a result, when an application is connected to a plugin, events from the plugin have a different type value. It becomes obvious that the event is being re-registered. How to get around this?

    2 answers 2

    So in dynamic library the copy of a static variable.

    You can add a static method with the "event type registry" parameter to the event class (for example, a wrapper over std::map<std::string, QEvent::Type> - name-> type).

    In the main program, create a Singleton registry and pass the link / pointer to its instance in the plugin.

    • Yes you are right. But the source of the problem is rather not that the plugin has its own copy of a static variable, but that QEvent::registerEventType() is called twice and re-registers the event type to a new value. And to find out whether the type of event has already been registered or not yet - the possibility of what is called out of the box is none. Is there no other possibility than to drag the instance list of names and values ​​of event types to the plugin? - alexis031182
    • one
      Need a connection between the program and the plugin to synchronize the registered types. I offered one option how to implement such a connection - Maxim Timakov
    • Thank. You see, the interest in what is being done, as I understood it, is re-registration of the type when the plug-in is connected (in the question). That is, the plug-in instance knows that such a value is already reserved. Is it not possible to somehow beat the situation so that if the type is already reserved, then use the existing value instead of registering a new one? - alexis031182
    • So the registry is for this and needed - if the event is not registered, then it is added to it, otherwise the number is taken from the registry. - Maxim Timakov
    • Yes, I understand, I mean, if the registry values ​​are somehow divided between the application and the plugin, it turns out that it is irrational to keep your copy of the registry according to your event types and bring it from the application to the plugin. There is already a global registry, you only need to clarify whether a previously defined value was entered into it or not. If you have already made it, then by the constant name of the event type (by line) we get the value. But unfortunately QEvent no such method. I'll try in the source to see how the trolls generally achieve data separability between the plugin and the program. - alexis031182

    The code from the QEvent source code that divides the registry of user events between the application and the plugins:

     #include <QtCore/QCoreApplication> template <size_t N> struct QBasicAtomicBitField { enum { BitsPerInt = std::numeric_limits<uint>::digits, NumInts = (N + BitsPerInt - 1) / BitsPerInt, NumBits = N }; QBasicAtomicInteger<uint> next; QBasicAtomicInteger<uint> data[NumInts]; bool allocateSpecific(int which) { QBasicAtomicInteger<uint> &entry = data[which / BitsPerInt]; const uint old = entry.load(); const uint bit = 1U << (which % BitsPerInt); return !(old & bit) && entry.testAndSetRelaxed(old, old | bit); } int allocateNext() { for(uint i = next.load(); i < NumBits; ++i) { if(allocateSpecific(i)) { const uint oldNext = next.load(); next.testAndSetRelaxed(oldNext, qMax(i + 1, oldNext)); return i; } } return -1; } }; typedef QBasicAtomicBitField<QEvent::MaxUser-QEvent::User+1> UserEventTypeRegistry; static UserEventTypeRegistry userEventTypeRegistry; static inline int registerEventTypeZeroBased(int id) { if(id < UserEventTypeRegistry::NumBits && id >= 0 && userEventTypeRegistry.allocateSpecific(id)) return id; return userEventTypeRegistry.allocateNext(); } 

    Checking that the event has already been registered is almost identical to the registration function, except that it does not register a new event:

     static inline int isEventRegistered(int id) { if(id < UserEventTypeRegistry::NumBits && id >= 0 && userEventTypeRegistry.allocateSpecific(id)) return id; return -1; } 

    Register a new event or return a value already registered:

     static inline int regEventType(int hint) { const int id = QEvent::MaxUser - hint; int result = isEventRegistered(id); if(result < 0) result = registerEventTypeZeroBased(id); return result < 0 ? -1 : QEvent::MaxUser - result; } 

    A static class method that allows you to receive event types by class name by transparently registering new ones:

     int EventHelper::registerEventType(const QString &class_name) { if(class_name == QLatin1String("MyEventOne")) return regEventType(QEvent::User + 1000); else if(class_name == QLatin1String("MyEventTwo")) return regEventType(QEvent::User + 1001); return regEventType(-1); } 

    Thus, it becomes possible to make the separation of event types between the application and the plug-ins, without transferring a static list to these plug-ins. Everything, it turns out, will be collected in one place.