Spec-Zone.ru › Qt 5.15

Создание пользовательских типов Qt

Обзор

При создании пользовательских интерфейсов с Qt, особенно тех, которые содержат специализированные элементы управления и функции, разработчики иногда нуждаются в создании новых типов данных, которые могут использоваться наряду или вместо существующего набора типов значений Qt.

Стандартные типы, такие как QSize, QColor и QString, могут храниться в объектах QVariant, использоваться в качестве типов свойств в классах на основе QObject и передаваться в коммуникации «сигнал-слот».

В данном документе мы рассмотрим пользовательский тип и опишем, как интегрировать его в модель объектов Qt, чтобы он хранился так же, как и стандартные типы Qt. Затем мы покажем, как зарегистрировать пользовательский тип, чтобы его можно было использовать в подключениях сигналов и слотов.

Создание пользовательского типа

Прежде чем начать, необходимо убедиться, что создаваемый нами пользовательский тип соответствует всем требованиям, налагаемым QMetaType. Другими словами, он должен предоставлять:

  • публичный конструктор по умолчанию,
  • публичный конструктор копирования и
  • публичный деструктор.

Следующее определение класса Message включает эти члены:

class Message
{
public:
    Message() = default;
    ~Message() = default;
    Message(const Message &) = default;
    Message &operator=(const Message &) = default;

    Message(const QString &body, const QStringList &headers);

    QString body() const;
    QStringList headers() const;

private:
    QString m_body;
    QStringList m_headers;
};

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

Объявление типа с помощью QMetaType

Классу Message требуется только подходящая реализация для его использования. Однако система типов Qt не сможет понять, как хранить, извлекать и сериализовать экземпляры этого класса без какой-либо помощи. Например, мы не сможем сохранить значения Message в QVariant.

Класс в Qt, отвечающий за пользовательские типы, — это QMetaType. Чтобы сделать тип известным этому классу, вызываем макрос Q_DECLARE_METATYPE() для класса в файле заголовков, где он определен:

Q_DECLARE_METATYPE(Message);

Это теперь позволяет хранить значения Message в объектах QVariant и извлекать их позже. Обратитесь к примеру пользовательского типа для кода, демонстрирующего это.

Макрос Q_DECLARE_METATYPE() также позволяет использовать эти значения в качестве аргументов сигналов, но только в прямых подключениях «сигнал-слот». Для того, чтобы пользовательский тип был доступен в общем случае для механизма сигналов и слотов, нам нужно выполнить некоторую дополнительную работу.

Создание и уничтожение пользовательских объектов

Хотя объявление в предыдущем разделе делает тип доступным для использования в прямых подключениях «сигнал-слот», он не может использоваться для очередей «сигнал-слот», таких как те, которые создаются между объектами в разных потоках. Это связано с тем, что метаобъектная система не знает, как обработать создание и уничтожение объектов пользовательского типа во время выполнения.

Чтобы включить создание объектов во время выполнения, вызовите шаблонную функцию qRegisterMetaType() для регистрации его в метаобъектной системе. Это также делает тип доступным для очередных соединений «сигнал-слот», при условии, что вы вызовете его до создания первого соединения, использующего этот тип.

Пример очередного пользовательского типа объявляет класс Block, который регистрируется в файле main.cpp:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    ...
    qRegisterMetaType<Block>();
    ...
    return app.exec();
}

Этот тип используется позже в соединении «сигнал-слот» в файле window.cpp:

Window::Window(QWidget *parent)
    : QWidget(parent), thread(new RenderThread(this))
{
    ...
    connect(thread, &RenderThread::sendBlock,
            this, &Window::addBlock);
    ...
    setWindowTitle(tr("Queued Custom Type"));
}

Если тип используется в очередном подключении без регистрации, на консоли будет выведено предупреждение; например:

QObject::connect: Cannot queue arguments of type 'Block'
(Make sure 'Block' is registered using qRegisterMetaType().)

Вывод типа в удобочитаемом формате

Часто бывает полезно выводить пользовательский тип в удобочитаемом формате для отладки, как показано в следующем коде:

    Message message(body, headers);
    qDebug() << "Original:" << message;

Это достигается путем создания оператора потока для типа, который часто определяется в файле заголовков для этого типа:

QDebug operator<<(QDebug dbg, const Message &message);

Реализация для типа Message в примере пользовательского типа прилагает усилия для обеспечения максимальной удобочитаемости выводного представления:

QDebug operator<<(QDebug dbg, const Message &message)
{
    const QString body = message.body();
    QVector<QStringRef> pieces = body.splitRef(QLatin1String("\r\n"), Qt::SkipEmptyParts);
    if (pieces.isEmpty())
        dbg.nospace() << "Message()";
    else if (pieces.size() == 1)
        dbg.nospace() << "Message(" << pieces.first() << ")";
    else
        dbg.nospace() << "Message(" << pieces.first() << " ...)";
    return dbg.maybeSpace();
}

Выводимая в отладочный поток информация, безусловно, может быть столь же простой или столь же сложной, как вам нужно. Обратите внимание, что значение, возвращаемое этой функцией, является самим объектом QDebug, хотя это часто достигается вызовом члена maybeSpace() объекта QDebug, который добавляет пробелы в поток для повышения удобочитаемости.

Дополнительная информация

Документация макроса Q_DECLARE_METATYPE() и функции qRegisterMetaType() содержат более подробную информацию об их использовании и ограничениях.

Примеры пользовательского типа и очередного пользовательского типа демонстрируют, как реализовать пользовательский тип с функциями, описанными в данном документе.

Документ Методы отладки предоставляет обзор отладочных механизмов, обсуждаемых выше.

END_OF_DOCUMENT_MARKER

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.15/custom-types.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API