Команда (фрилансеры)

Набираем команду фрилансеров, Вы:

  • Программист,
  • Дизайнер,
  • SEO-специалист,
  • Менеджер

Разработка на заказ

Наша команда фрилансеров выполнит
работы на заказ:

Создание и раскрутка сайтов
Разработка приложений (мобайл, десктоп, сервер)
Разработка игр (веб, мобайл, 3D)
Аутсорсинг, фриланс

Контакты
vk.com/sitev_ru
Skype: sitev.ru
E-mail: mike@sitev.ru
github.com/sitev

Рейтинг@Mail.ru

Besucherzahler
счетчик посещений
Сайт на C++
Наш сайт работает на C++ и это очень круто! =))

QML C++. Урок 3

Самой лучшей моделью программы на Qt, я думаю, будет такая: дизайн на QML, а код на C++.

QML легко расширяется с помощью кода C++. Объектами QML можно манипулировать в C++, и, наоборот, С++ можно вызывать непосредственно из QML.

Загрузка QML объектов из C++

QML может быть загружен 2-мя способами, с помощью QQmlComponent или QQuickView.

В чём различия?

QQmlComponent загружает QML как объект C++, который затем может быть изменен из C++ кода.

QQuickView является потомком QWindow класса (через QQuickWindow), поэтому, в этом случае, QML не только загружается, но и отображается визуально. QQuickView, как правило, используется для отображения QML в пользовательском интерфейсе приложения.

Например, предположим, что есть MyItem.qml файл:

import QtQuick 2.0

Item {
    width: 100; height: 100
}

Использование QQmlComponent требует вызова QQmlComponent::create(), чтобы создать новый экземпляр компонента:

// Using QQmlComponent
QQmlEngine engine;
QQmlComponent component(&engine, QUrl::fromLocalFile("MyItem.qml"));
QObject *object = component.create();
...
delete object;

QQuickView создает экземпляр компонента автоматически, который доступен через QQuickView::rootObject():

// Using QQuickView
QQuickView view;
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
QObject *object = view.rootObject();

Этот object является экземпляром класса Item из MyItem.qml. Теперь можно менять его свойства либо с помощью QObject::SetProperty(), либо с помощью QQmlProperty:

object->setProperty("width", 500);
QQmlProperty(object, "width").write(500);

Есть и другой, возможно, более правильный способ. В QML тип объектов Item тоже самое, что и в C++ класс QQuickItem. Приводим к этому классу и вуаля:

QQuickItem *item = qobject_cast<QQuickItem*>(object);
item->setWidth(500);

Доступ к загруженным QML-объектам

QML-компоненты могут содержать в себе дочерние объекты, которые, в свою очередь, также могут содержать в себе дочерние объекты и т.д., образуя при этом дерево объектов. Дочерние объекты можно искать с помощью QObject::findChild(), используя свойство QObject::objectName. Например:

import QtQuick 2.0

Item {
    width: 100; height: 100

    Rectangle {
        anchors.fill: parent
        objectName: "rect"
    }
}

... ищем для Item дочерний элемент Rectangle и устанавливаем цвет прямоугольника в красный:

QObject *rect = object->findChild<QObject*>("rect");
if (rect) rect->setProperty("color", "red");

Дочерних элементов с одним и тем же именем может быть несколько, их можно найти с помощью другой функции QObject::findChildren().

Доступ свойствам QML-объектов

Любые свойства, объявленные в объекте QML, автоматически доступны из C++, например:

// MyItem.qml
import QtQuick 2.0

Item {
    property int someNumber: 100
}

Значение someNumber может быть установлено или прочитано с помощью QQmlProperty или QObject::SetProperty() и QObject::property():

qDebug() << "Property value:" << QQmlProperty::read(object, "someNumber").toInt();
QQmlProperty::write(object, "someNumber", 5000);

qDebug() << "Property value:" << object->property("someNumber").toInt();
object->setProperty("someNumber", 100);

Вызов методов QML

На языке QML можно писать свой код. Он пишется на Javascript (для кого-то это разрыв мозга, но это так). И эти функции (или методы) могут быть вызваны из C++ с использованием QMetaObject::InvokeMethod(). Параметры метода и возвращаемых значений, переданные из QML, всегда переводятся в тип QVariant.

Давайте рассмотрим пример:

// MyItem.qml
import QtQuick 2.0

Item {
    function myQmlFunction(msg) {
        console.log("Got message:", msg)
        return "some return value"
    }
}
// main.cpp
QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();

QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
        Q_RETURN_ARG(QVariant, returnedValue),
        Q_ARG(QVariant, msg));

qDebug() << "QML function returned:" << returnedValue.toString();
delete object;

Подключение к сигналам QML

Все сигналы QML автоматически доступны для C++, и могут быть подключены к использованию QObject::connect(), как и любой сигнал Qt C++. В свою очередь, любой сигнал C++ может быть получен с помощью объекта QML с использованием обработчиков сигналов:

Например, компонент QML с сигналом qmlSignal. Этот сигнал подключается к слоту cppSlot() на C++ с помощью QObject::connect(). Метод cppSlot() вызывается всякий раз по сигналу qmlSignal:

// MyItem.qml
import QtQuick 2.0

Item {
    id: item
    width: 100; height: 100

    signal qmlSignal(string msg)

    MouseArea {
        anchors.fill: parent
        onClicked: item.qmlSignal("Hello from QML")
    }
}
// C++
class MyClass : public QObject
{
    Q_OBJECT
public slots:
    void cppSlot(const QString &msg) {
        qDebug() << "Called the C++ slot with message:" << msg;
    }
};

int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);

    QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
    QObject *item = view.rootObject();

    MyClass myClass;
    QObject::connect(item, SIGNAL(qmlSignal(QString)),
                     &myClass, SLOT(cppSlot(QString)));

    view.show();
    return app.exec();
}

А если мы хотим использовать тип объектов QML в качестве параметров? Тогда в QML вместо типа необходимо задать слово var, а в C++ будем использовать QVariant:

// MyItem.qml
import QtQuick 2.0

Item {
    id: item
    width: 100; height: 100

    signal qmlSignal(var anObject)

    MouseArea {
        anchors.fill: parent
        onClicked: item.qmlSignal(item)
    }
}
// C++
class MyClass : public QObject
{
    Q_OBJECT
public slots:
    void cppSlot(const QVariant &v) {
       qDebug() << "Called the C++ slot with value:" << v;

       QQuickItem *item =
           qobject_cast<QQuickItem*>(v.value<QObject*>());
       qDebug() << "Item dimensions:" << item->width()
                << item->height();
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
    QObject *item = view.rootObject();

    MyClass myClass;
    QObject::connect(item, SIGNAL(qmlSignal(QVariant)),
                     &myClass, SLOT(cppSlot(QVariant)));

    view.show();
    return app.exec();
}

QML + C++ на практике

Это всё была голая теория. Давайте реализуем всё это на практике!

Запускаем Qt Creator и создаём новый проект lesson3 (приложение Qt Quick). Как мы уже писали тут, создаются три файла: main.cpp, main.qml и MainForm.ui.qml.

Изучаем main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

Тааак... И где тут QQmlComponent или QQuickView? Чуть выше мы писали, что "QML может быть загружен 2-мя способами, с помощью QQmlComponent или QQuickView". Видимо, это новый, более продвинутый подход, теперь нужно использовать QQmlApplicationEngine. По логике, этот способ очень близок к QQuickView. У QQmlApplicationEngine есть метод rootObjects() - список корневых объектов, то есть корневых объектов несколько, а не один, как у QQuickView.

Теперь изучим main.qml:

import QtQuick 2.6
import QtQuick.Window 2.2

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    MainForm {
        anchors.fill: parent
        mouseArea.onClicked: {
            console.log(qsTr('Clicked on background. Text: "' + textEdit.text + '"'))
        }
    }
}

Получается, что здесь только один корневой объект, это Window, получим указатель на него:

    QList<QObject*> lst = engine.rootObjects();
    int count = lst.count();
    qDebug() << count; //Убеждаемся, что кол-во объектов один!
    if (count == 0) return -1; //Ошибка, выходим из приложения

    QObject *object = lst[0];

Он это или не он? Чтобы точно убедиться в этом, возьмём у Window свойства width и title:

    qDebug() << "width: " << QQmlProperty::read(object, "width").toInt();
    qDebug() << "width: " << QQmlProperty::read(object, "title").toString();

Точно они!

А давайте поменяем текст в поле вводе, сейчас там находится следующее "Enter some text...". Для этого зададим имя objectName: "mainForm" для MainForm в main.qml и имя objectName: "textEdit1" для TextEdit в MainForm.ui.qml. Теперь мы сможем искать его по этому имени:

    QObject *mainForm = object->findChild<QObject*>("mainForm");
    if (mainForm) {
        QObject *textEdit1 = mainForm->findChild<QObject*>("textEdit1");
        if (textEdit1) {
            qDebug() << "text:" << textEdit1->property("text");
            textEdit1->setProperty("text", "Hello from C++");
        }
        else qDebug() << "textEdit1 == null";
    }
    else qDebug() << "mainForm == null";

Запускаем приложение - работает!

В этом уроке мы попытались разобраться, как "подружить" QML и C++. Надеюсь у нас это получилось.

P.S. Здесь Вы сможете найти исходники урока №3: github.com/sitev/qt


  • - 2017-09-19 08:23:38

  • - 2017-12-13 00:54:31

    хорошая статья спасибки...

Отправить комментарий
Наш проект: язык Cj
Cj - язык программирования (C++ & Javascript)
Новый язык программирования, для разработки веб, мобайл, десктоп-приложений, игр... подробнее...

Хотите поддержать проект?

  • Оставляйте ссылки на наш сайт
  • Станьте спонсором проекта
подробнее...

Концепция SITEV.ru

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

Реклама


Поиск работы по всему миру