Qt: определение пользовательского типа события

Я создал пользовательское событие в своем приложении Qt, создав подкласс QEvent.

class MyEvent : public QEvent
{
  public:
    MyEvent() : QEvent((QEvent::Type)2000)) {}
    ~MyEvent(){}
}

Чтобы проверить это событие, я использую следующий код в методе event():

if (event->type() == (QEvent::Type)2000)
{
  ...
}

Я хотел бы иметь возможность определить тип пользовательского события где-нибудь в моем приложении, чтобы мне не нужно было указывать фактическое целое число в моих методах событий. Итак, в моих методах event() я хотел бы иметь возможность делать что-то вроде

if (event->type() == MyEventType)
{
  ...
}

Любые мысли, как и где в коде я мог бы это сделать?


person Chris    schedule 11.02.2010    source источник
comment
Вместо магической константы 2000 можно использовать QEvent::User.   -  person Ton van den Heuvel    schedule 13.02.2010
comment
@TonvandenHeuvel: +1. Также. Вместо «можно использовать» я бы сказал следует использовать. ;)   -  person Macke    schedule 28.01.2013


Ответы (3)


Если тип события идентифицирует ваш конкретный класс, я бы поместил его туда:

class MyEvent : public QEvent {
public:
    static const QEvent::Type myType = static_cast<QEvent::Type>(2000);
    // ...
};

// usage:
if(evt->type() == MyEvent::myType) {
    // ...
}
person Georg Fritzsche    schedule 11.02.2010
comment
Это очень помогло, спасибо! Хотя я не совсем понимаю, почему вы сделали ревизию, которую вы сделали. - person Chris; 12.02.2010
comment
Если он инициализирован в определении класса, его можно использовать в целочисленных константных выражениях, например, с case в операторах switch или в качестве границ массива. - person Georg Fritzsche; 12.02.2010

Для удобства вы можете использовать статическую функцию QEvent::registerEventType(), чтобы зарегистрировать и зарезервировать пользовательский тип события для вашего приложения. Это позволит вам избежать случайного повторного использования пользовательского типа события, который уже используется в другом месте вашего приложения.

Пример:

class QCustomEvent : public QEvent
{
public:
    QCustomEvent() : QEvent(QCustomEvent::type())
    {}

    virtual ~QCustomEvent()
    {}

    static QEvent::Type type()
    {
        if (customEventType == QEvent::None)
        {
            int generatedType = QEvent::registerEventType()
            customEventType = static_cast<QEvent::Type>(generatedType);
        }
        return customEventType;
    }

private:
    static QEvent::Type customEventType;
};

QEvent::Type QCustomEvent::customEventType = QEvent::None;
person Ostap    schedule 24.11.2010
comment
Это хорошее предложение, но вы можете пропустить часть QEvent::None: const QEvent::Type CustomEvent::EventType = static_cast‹QEvent::Type›(QEvent::registerEventType()); - person Lily B; 26.12.2010
comment
И называть ваш пример QCustomEvent не очень умно: это имя класса Qt 3. - person Lily B; 26.12.2010
comment
Кроме того, вам не нужна переменная-член. Просто используйте статический локальный. - person Jake Petroules; 09.03.2013
comment
ВНИМАНИЕ Это плохой совет. Этот код будет работать, только если у вас есть один пользовательский тип события. Вы не можете быть производными от этого класса QCustomEvent! - person Kuba hasn't forgotten Monica; 01.10.2013

Идиоматический способ решения таких проблем — создать класс-оболочку шаблона, используя CRTP. Для каждого пользовательского типа события такой шаблон представляет новый тип, поэтому для каждого типа существует отдельный элемент staticType(), возвращающий его уникальный зарегистрированный тип.

Ниже я даю три способа определения типов:

  1. По staticType() -- это полезно только внутри вызова приложения, и этот тип следует использовать с QEvent. Не гарантируется, что значения останутся неизменными между вызовами приложения. Им не место в постоянном хранилище, например в журнале.

  2. К localDurableType() -- они будут сохраняться между вызовами и между повторными компиляциями с одним и тем же компилятором. Он сохраняет ручное определение метода durableType() при определении сложных событий.

  3. По durableType() - это действительно кроссплатформенные и будут одинаковыми, если вы не измените имена классов событий в своем коде. Вы должны вручную определить durableType(), если вы не используете макрос NEW_QEVENT.

И localDurableType(), и durableType() различаются между Qt 4 и 5 из-за изменений в qHash.

Вы используете заголовок одним из двух способов:

#include "EventWrapper.h"

class MyComplexEvent : public EventWrapper<MyComplexEvent> {
   // An event with custom data members
   static int durableType() { return qHash("MyEvent"); }
   ...
};

NEW_QEVENT(MySimpleEvent) // A simple event carrying no data but its type.

EventWrapper.h

#ifndef EVENTWRAPPER_H
#define EVENTWRAPPER_H

#include <QEvent>
#include <QHash>

template <typename T> class EventWrapper : public QEvent {
public:
   EventWrapper() : QEvent(staticType())) {}
   static QEvent::Type staticType() {
      static int type = QEvent::registerEventType();
      return static_cast<QEvent::Type>(type);
   }
   static int localDurableType() {
      static int type = qHash(typeid(T).name());
      return type;
   }
};

#define NEW_QEVENT(Name) \
   class Name : public EventWrapper< Name > \
   { static int durableType() { \
       static int durable = qHash(#Name); return durable; \
     } };

#endif // EVENTWRAPPER_H
person Kuba hasn't forgotten Monica    schedule 01.10.2013
comment
Мне нравится использование CRTP здесь, но мне интересно, как вы будете уверены, что варианты, использующие qHash, не конфликтуют с существующими типами событий? - person Kamajii; 01.01.2017
comment
Вы не можете быть уверены в целом, но вы можете быть уверены в любой конкретной программе. Вы можете статически проверить наличие коллизий и получить ответ «да, есть коллизии» или «нет, коллизий нет». Итак, иногда тот факт, что нет никакого способа узнать в целом, не исключает возможности узнать это в конкретных обстоятельствах. - person Kuba hasn't forgotten Monica; 03.01.2017
comment
Но разве это не очень важный момент, который следует упомянуть в вашем ответе? Наконец, вы не включаете в свой код никаких положений против коллизий. - person Kamajii; 03.01.2017
comment
Сам код не имеет большого значения. Вы бы использовали статическую проверку, чтобы проверить наличие коллизий или их отсутствие. - person Kuba hasn't forgotten Monica; 03.01.2017