Класс QVariant может содержать значения многих типов Qt, включая QBrush, QColor, QCursor, QDateTime, QFont, QKeySequence, QPalette, QPen, QPixmap, QPoint, QRect, QRegion, QSize и QString, а также такие основные числовые типы С++, как double и int. Класс QVariant может, кроме того, содержать контейнеры QMap, QStringList и QList.
Широкое распространение получило применение этого типа в классах отображения элементов, в модуле баз данных и в классе QSettings, позволяя считывать и записывать данные элементов, данные базы данных и пользовательские настройки в виде любого значения, допускаемого типом QVariant. Пример этого мы уже видели в главе 3, когда объекты QRect, QStringList и пара булевых значений передавались функции QSettings::setValue() и затем считывались как объекты QVariant.
Можно создавать произвольно сложные структуры данных, используя тип QVariant для обеспечения вложенных структур контейнеров:
QMap pearMap;
pearMap["Standard"] = 1.95;
pearMap["Organic"] = 2.25;
QMap fruitMap;
fruitMap["Orange"] = 2.10;
fruitMap["Pineapple"] = 3.85;
fruitMap["Pear"] = pearMap;
Здесь мы создали отображение со строковыми ключами (названия продукции) и значениями, которыми могут быть либо числа с плавающей точкой (цены), либо отображения. Отображение верхнего уровня содержит три ключа: «Orange», «Pear» и «Pineapple» (апельсин, груша и ананас). Значение, связанное с ключом «Реаг», является отображением, содержащим два ключа «Standard» и «Organic» (стандартный и экологически чистый). При проходе по ассоциативному массиву, содержащему объекты QVariant, нам необходимо использовать функцию type() для проверки находящегося в QVariant типа, чтобы можно было его правильно обработать.
Способ создания подобным образом структур данных может быть очень привлекательным, поскольку мы можем создавать любые структуры данных. Но удобство применения типа QVariant достигается за счет снижения эффективности и читаемости программы. Для хранения наших данных, как правило, предпочтительнее использовать соответствующий класс языка С++ там, где это возможно.
QVariant используется мета-объектной системой Qt и поэтому является частью модуля QtCore. Тем не менее, когда мы собираем приложение с модулем QtGui, QVariant может хранить такие типы, связанные с графическим пользовательским интерфейсом, как QColor, QFont, QIcon, QImage или QPixmap:
QIcon icon("open.png");
QVariant variant = icon;
Для извлечения значений этих типов из QVariant мы можем следующим образом использовать шаблонную функцию—член QVariant::value():
QIcon icon = variant.value();
Функция value() также может использоваться для преобразования между типами неграфического интерфейса и типом QVariant, однако на практике обычно используются функции преобразования вида to…() (например, toString()) для преобразования типов неграфического интерфейса.
QVariant может также использоваться для хранения пользовательских типов данных при условии обеспечения ими стандартного конструктора и конструктора копирования. Чтобы это заработало, прежде всего необходимо зарегистрировать тип, используя макрос Q_DECLARE_METATYPE() обычно в заголовочном файле после определения класса:
Q_DECLARE_METATYPE(BusinessCard)
Это позволяет нам написать следующий программный код:
BusinessCard businessCard;
QVariant variant = QVariant::fromValue(businessCard);
if (variant.canConvert()) {
BusinessCard card = variant.value();
}
Эти шаблонные функции—члены не будут работать с компилятором MSVC 6 из-за ограничений последнего. Если вы не можете отказаться от этого компилятора, вместо указанных функций используйте глобальные функции qVariantFromValue(), qVariantValue() и qVariantCanConvert().
Если в пользовательском типе данных предусмотрены операторы << и >> для записи и чтения из потока данных QDataStream, их можно зарегистрировать, используя функцию qRegisterMetaTypeStreamOperators(). Это позволяет, среди прочего, хранить параметры настройки пользовательских типов данных, используя QSettings. Например:
qRegisterMetaTypeStreamOperators("BusinessCard");