пятница, 17 июня 2011 г.

Добавление своего типа в QVariant

Хороший тип QVariant. Это может быть int, double, QDate, QMap, и еще полсотни типов.
Добавим к этим типам собственный класс или структуру, чтобы с ней можно было бы общаться как с другими типами - помещать и извлекать из QVariant.

class SomeClass
{
//всё что нужно
};
Q_DECLARE_METATYPE(SomeClass)


Итак, достаточно после определения класса вызвать макрос Q_DECLARE_METATYPE()
Что это дает?

Помещаем экземпляр класса в QVariant.

SomeClass scl;
QVariant vclass = QVariant::fromValue(scl);


Всё, теперь экземпляр класса SomeClass, хранится как QVariant и с ним можно делать всё, что и с объектами типа QVariant.

Обратное преобразование.

scl = qvariant_cast(vclass);

Вообще говоря, в классе SomeClass крайне желательно определить оператор присваивания и конструктор копирования, на случай если вдруг возникнет желание помещать его в контейнер типа QList. Если это обычная структура, то ничего страшного, конечно, не произойдет, элементы структуры скопируются компилятором.

Теперь об одной особенности макроса Q_DECLARE_METATYPE(). Он не приемлет запятых в определении.
Написать что-то типа
Q_DECLARE_METATYPE(QVector<QPair<QString, QString> >)
не получится, из-за запятой в определении шаблона.
Лечится это хитрым патчем.

#define Q_DECLARE_METATYPE_COMMA(...) \
QT_BEGIN_NAMESPACE \
template <> \
struct QMetaTypeId< __VA_ARGS__ > \
{ \
    enum { Defined = 1 }; \
  static int qt_metatype_id() \
  { \
     static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
     if (!metatype_id) \
        metatype_id = qRegisterMetaType< __VA_ARGS__ >( #__VA_ARGS__, \
          reinterpret_cast< __VA_ARGS__ *>(quintptr(0))); \
     return metatype_id; \
  } \
}; \
QT_END_NAMESPACE \

Я даже не буду рассказывать, что здесь делается т.к. сам не понимаю и хитрый патч вытащен откуда-то из просторов интернета.
Главное, что с его помощью мы можем написать
Q_DECLARE_METATYPE_COMMA(QVector<QPair<QString, QString> >)

* This source code was highlighted with Source Code Highlighter.
 И тогда мы сможем назначить typedef
typedef QVector<QPair<QString, QString> > VectorPair;
Q_DECLARE_METATYPE_COMMA(VectorPair)


* This source code was highlighted with Source Code Highlighter.

и использовать тип VectorPair как QVariant.

6 коммент.:

  1. АнонимныйJun 17, 2011 09:07 AM

    парсер съел SomeClass в
    scl = qvariant_cast< SomeClass >(vclass);

    и если же объявлено
    typedef QVector< QPair< QString, QString > > VectorPair;
    то можно писать Q_DECLARE_METATYPE(VectorPair) не прибегая к Q_DECLARE_METATYPE_COMMA

    ОтветитьУдалить
  2. Спасибо за замечание. Действительно съел. Вообще что-то мне не нравится blogspot - не подходит он для программистских постов. Нету тега code.
    Я бы и рад перебраться куда-нибудь да уже столько сюда напостил - жалко бросать.
    Геморроя много с подсветкой кода. Может гугловцы когда нибудь разродтся сделать что-то более удобное.
    По поводу Q_DECLARE_METATYPE_COMMA то он всё таки нужен.

    ОтветитьУдалить
  3. Извините, что влез немного не по теме, но...

    Вы не знаете как сконвертировать файлы проекта QtCreator (.pro) в файлы проекта studio 2010 (.vcxproj)?

    ОтветитьУдалить
  4. Знаем. У вас в системе есть тулза qmake.
    Вам нужно написать команду
    qmake -tp vc file.pro

    ОтветитьУдалить
  5. Спасибо, Cyril Kissel. Это - то что нужно!

    ОтветитьУдалить
  6. Здравствуйте. Какой шаблон для блога вы используете?

    ОтветитьУдалить