Форум программистов, компьютерный форум, киберфорум
Wyn
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

Взаимодействие между QML и C++

Запись от Wyn размещена 29.04.2016 в 15:12
Показов 7875 Комментарии 0
Метки c++, c++ qt, javascript, qt qml

Общий QML

Оглавление
  1. Основы
    1. Правила QML
    2. Свойства и соединения
    3. Динамическое создание объектов
    4. JavaScript
    5. Перевод приложения
  2. Взаимодействие между QML и C++
    1. Основы
      1. Нерегистрируемые в QML объекты
      2. Регистрируемые в QML объекты
    2. Реализация специфичных для QML типов и аттрибутов
      1. Прикреплённые объекты и аннотации
      2. Модификаторы свойств
      3. Определение свойства по-умолчанию для QML-объектов в С++
      4. Получение уведомлений об инициализации объекта
  3. Рекомедации
    1. Общие рекомендации
    2. Оформление кода
    3. Масштабируемость
    4. Оптимизации
  4. Полезности
    1. Общие
      1. Двунаправленное соединение
      2. Скрытые свойства в подключаемом элементе
      3. Неизменяемое снаружи свойство в подключаемом элементе, которое можно изменять внутри
      4. Реализация класса асинхронной загрузки изображений
    2. Работа с компонентами
      1. StackView(controls1)
  5. Специфика платформ(пока нет)
    1. Android
    2. iOS
    3. Linux
    4. Windows
  6. Список ссылок и литературы

Взаимодействие между QML и C++
http://doc.qt.io/qt-5/qtqml-cp... topic.html

Основы

QML использует метаобъектную систему Qt. Поэтому объект С++, который нужно применять в QML, должен всегда прямо или косвенно наследоваться от QObject. При этом все свойства(объявляемые макросом Q_PROPERTY), слоты и сигналы данного объекта будут доступны в QML. Обычные функции объекта делаются доступными в QML с помощью макроса Q_INVOKABKE.

Объекты взаимодейтствия между Qt и QML в основном разделяются на два типа:
  • Нерегистрируемые
  • Регистрируемые

Нерегистрируемые в QML объекты

Нерегистрируемые объекты представляют собой классы, унаследованные от QObject или любой другой объект(int, bool, QUrl и т.д.), который можно преобразовать в базовый тип QML. Они вносятся в контекст QML под определённым именем, через которое к ним и получают доступ.
Пример
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ApplicationData : public QObject
{
    Q_OBJECT
public:
    Q_INVOKABLE QDateTime getCurrentDateTime() const {
        return QDateTime::currentDateTime();
    }
};
 
int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);
 
    QQuickView view;
 
    ApplicationData data;
    view.rootContext()->setContextProperty("applicationData", &data);
 
    view.setSource(QUrl::fromLocalFile("MyItem.qml"));
    view.show();
 
    return app.exec();
}
JavaScript
1
2
3
4
// MyItem.qml
import QtQuick 2.0
 
Text { text: applicationData.getCurrentDateTime() }

В таком случае возникает проблема, если надо каким-то образом в QML привязать слот в подсоединённом объекте с какими-либо свойствами или сигналами других объектов. В этом случае нужно применять QML класс Binding.
Пример
JavaScript
1
2
3
4
5
6
7
8
9
Text {
    text: applicationData.getCurrentDateTime() // applicationData - подсоединённые объект
 
    Binding {
        target: applicationData
        property: "someProperty"
        value: "someValue" // значение, которое вешается на свойство someValue объекта applicationData
    }
}


Регистрируемые в QML объекты

Любой унаследованный от QObject класс может быть зарегистрирован как QML-объект.

С++: QML разделяет классы регистрируемых объектов на виды:
  1. Закрытые для QML. Регистрируются помощью qmlRegisterType без параметров. Данный тип нельзя создавать в QML и к нему нельзя обращаться. К примеру, если зарегистрировать подобный класс как базовый, а класс-наследник как обычный, то в QML нельзя будет получить доступ из класса наследника к свойствам, сигналам и другой мета-информации, унаследованной от подобного базового класса.

  2. Интерфейсы. Регистрируются с помощью qmlRegisterInterface. Данный тип нельзя создавать, но можно к нему обращаться.

  3. Не создаваемые QML. Регистрируются с помощью qmlRegisterUncreatableType. Данный тип нельзя создавать в QML, но к нему можно обращаться. Это полезно, когда класс не должен создаваться в QML, но в тоже время его перечисляемые типы(enum) или свойства должны быть доступны из QML.

  4. Синглтоны. Регистрируются с помощью qmlRegisterSingletonType. Данный тип в единственном экземпляре автоматически создаётся QML(и уничтожается по окончанию работы) и к нему спокойно можно обращаться по его имени. Может быть не только QObject, но и QJSValue.

  5. Обычные объекты QML. Регистрируются с помощью qmlRegisterType с параметрами. Объекты данного типа можно спокойно создавать в QML и к ним можно обращаться.

  6. Расширение объектов. Регистрируются с помощью qmlRegisterExtendedType. Расширяют обычные объекты, предоставляя им дополнительные свойства.

    Пример обычного объекта QML
    C++ часть:
    C++ (Qt)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    class Message : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
        Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
    public:
        Q_INVOKABLE void do_some_operation();
        //...
    public slots:
        void do_some_other_operation();
        //...
    signals:
        void someSignal();
        // ...
    };
     
    #inclide <QtQml>
    qmlRegisterType<Message>("com.mycompany.messaging", 1, 0, "Message");
    QML часть:
    JavaScript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    import com.mycompany.messaging 1.0
     
    Message {
        author: "Amelie"
        creationDate: new Date()
     
        onSomeSignal: do_some_operation()
        
        Component.onCompleted: do_some_other_operation()
    }


Реализация специфичных для QML типов и аттрибутов

Прикреплённые объекты и аннотации
Создание прикреплённых типов и свойств.
Для реализации подобного рода функционала нужно в унаследованном от QObject классе определить функцию static <AttachedPropertiesType> *qmlAttachedProperties(QObject *object), которая должна возвратить прикреплённый объект. А сам класс обйявить с помощью QML_DECLARE_TYPEINFO как класс, имеющий прикреплённые свойства QML_HAS_ATTACHED_PROPERTIES.
Пример
Обычный класс QML, приведённые ранее:
C++ (Qt)
1
2
3
4
5
6
7
8
class Message : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
    Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
public:
    // ...
};
Прикреплённый класс:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
class MessageBoardAttachedType : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool expired READ expired WRITE expired NOTIFY expiredChanged)
public:
    MessageBoardAttachedType(QObject *parent);
    bool expired() const;
    void setExpired(bool expired);
signals:
    void published();
    void expiredChanged();
};
Обёртка прикреплённого класса:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
class MessageBoard : public QObject
{
    Q_OBJECT
public:
    static MessageBoard *qmlAttachedProperties(QObject *object)
    {
        return new MessageBoardAttachedType(object);
    }
};
QML_DECLARE_TYPEINFO(MessageBoard, QML_HAS_ATTACHED_PROPERTIES)
QML:
JavaScript
1
2
3
4
5
6
7
8
Message {
    author: "Amelie"
    creationDate: new Date()
 
    MessageBoard.expired: creationDate < new Date("January 01, 2015 10:45:00")
    MessageBoard.onPublished: console.log("Message by", author, "has been
published!")
}


Модификаторы свойств
Имеют в QML вид <ModifierType> on <propertyName>.
Есть два разных типа модификаторов свойств:
  1. Перехватчики записи свойств. Используются для модификации или фильтрования значений, когда они записываются в свойства. Ими, к примеру, является Behavior.
  2. Источники значений свойств. Используются для обновления свойств, например, для автоматического обновления свойств по времени. Ими, к примеру, являются различные типы анимаций свойств(property animation types).

Источники значений свойств реализуются в С++ посредством унаследования класса QQmlPropertyValueSource и реализации функционала, который записывает в свойство разные значения по времени.
Пример
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class RandomNumberGenerator : public QObject, public QQmlPropertyValueSource
{
    Q_OBJECT
    Q_INTERFACES(QQmlPropertyValueSource)
    Q_PROPERTY(int maxValue READ maxValue WRITE setMaxValue NOTIFY maxValueChanged);
public:
    RandomNumberGenerator(QObject *parent)
        : QObject(parent), m_maxValue(100)
    {
        qsrand(QDateTime::currentDateTime().toTime_t());
        QObject::connect(&m_timer, SIGNAL(timeout()), SLOT(updateProperty()));
        m_timer.start(500);
    }
 
    int maxValue() const;
    void setMaxValue(int maxValue);
 
    virtual void setTarget(const QQmlProperty &prop) { m_targetProperty = prop; }
 
signals:
    void maxValueChanged();
 
private slots:
    void updateProperty() {
        m_targetProperty.write(qrand() % m_maxValue);
    }
 
private:
    QQmlProperty m_targetProperty;
    QTimer m_timer;
    int m_maxValue;
};
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
import QtQuick 2.0
 
Item {
    width: 300; height: 300
 
    Rectangle {
        RandomNumberGenerator on width { maxValue: 300 }
 
        height: 100
        color: "red"
    }
}


Определение свойства по-умолчанию для QML-объектов в С++
С++ объект, который зарегистрирован как объект QML, может обладать свойством по-умолчанию(дефолтное свойство). Свойство по-умолчанию - это свойство к которому причисляются все подэлементы данного объекта, если их не причислить к другим свойствам. Свойство по-умолчанию может быть установлено с помощью установки в Q_CLASSINFO по ключу "DefaultProperty" необходимого свойства.
Пример
Ниже класс MessageBoard определяет его свойство messages(сообщения) как свойство по-умолчанию:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
class MessageBoard : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QQmlListProperty<Message> messages READ messages) // есть мнение, что здесь ошибка из-за copy-paste
                                                                                                                  // и должен быть указан ещё  метод записи - WRITE
    Q_CLASSINFO("DefaultProperty", "messages")
public:
    QQmlListProperty<Message> messages() const;
 
private:
    QList<Message *> messages;
};
JavaScript
1
2
3
4
MessageBoard {
    Message { author: "Naomi" } // Класс Message заносится в свойство по-умолчанию(в данном случае в свойство messages).
    Message { author: "Clancy" }
}


Получение уведомлений об инициализации объекта
Для некоторых QML объектов необходимо, чтобы некоторые операции происходили уже после их создания и инициализации. Специально для этих целей существует класс QQmlParserStatus. Для получения уведомлений С++ класс должен унаследовать QQmlParserStatus и проинформировать мета-систему Qt с помощью макроса Q_INTERFACES.
Пример
JavaScript
1
2
3
4
5
6
7
8
9
10
class MyQmlType : public QObject, public QQmlParserStatus
{
    Q_OBJECT
    Q_INTERFACES(QQmlParserStatus)
public:
    virtual void componentComplete()
    {
        // Провести необходимые операции, когда объект полностью создан
    }
};
Метки c++, c++ qt, javascript, qt qml
Размещено в Qt, QML
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Жара жесть.
kumehtar 18.08.2026
Пролетают летом дни Тридцать пять жары в тени. Каждый август год от года Дарит жаркую погоду.
Когда логика программы не спасает от человеческих ошибок
Maks 18.08.2026
В последнее время всё чаще и чаще сталкиваюсь с таким явлением, как абсолютная невнимательность (или глупость) пользователей. Проявляется это чаще всего на работе в коллективе. Допустим, человек с. . .
Лето уходит
kumehtar 17.08.2026
Мысли в слух
kumehtar 17.08.2026
Забавно, насколько сейчас стала доступна информация. Например о магии, духовном развитии, медитациях, и других подобных направлениях, ранее зачастую тайных, передаваемых от учителя к ученику. Хотя. . .
Перемещение строк из ТЧ в другой документ с учетом текущего пробега
Maks 17.08.2026
Реализация из решения ниже выполнена на примере нетипового документа "Автозапчасти", с ТЧ "Шины". За основу взят алгоритм отсюда: https:/ / www. cyberforum. ru/ blogs/ 359708/ 10838. html Задача: . . .
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru