Пользователь
0,0
рейтинг
25 февраля 2012 в 05:53

Разработка → QML и C++. Простой пример связки из песочницы

Qt*
image
QML технология красивая и радует глаз. Меня она очень заинтересовала, и я решил ее освоить. Но не тут то было, ибо я оказался тупым и беспомощным. Нигде в сети не нашел примера «для чайников» (наверно плохо искал), чтобы с нуля построить простейшее приложение QML и C++ в связке. Везде чего-то не хватало: или не учитывался Qt Creator, или код выдавал ошибки, или отсутствовали целые моменты, которые пользователи должны были сами знать. Официальная документация и примеры здесь на хабре также были с этими недостатками. Вот и решил после долгих попыток и ошибок написать такую статью для начинающих с подробнейшим описанием.

Задача. Нужно написать программу QML в связке с С++, где
1. На форме располагается кнопка, строка ввода, и поле вывода.
2. Требуется считать из строки ввода число, прибавляется 1, и ответ выводится в поле вывода.
3. Интерфейс написан на QML.
4. Функционал на С++, то есть нам нужно обеспечить взаимосвязь между QML и C++: кнопка QML вызывает С++ функцию, а функция меняет свойства QML объектов.


Создание базового приложение QML


Используем Qt Creator. Я использовал версию 2.3 с Qt 4.7.4
image
Создание QML приложения

1. Создаем GUI Приложение: Файл -> Новый файл или проект.... Там слева выбираем Проект Qt Widget, с справа GUI приложение Qt. Потом жмем внизу кнопку "Выбрать...".


2. В следующем окне выбираем название нашего проекта (без пробелов и русских букв). Например, в нашем случае это "Example".


3. В следующем окне у Вас должна стоять галочка у "Desktop". Если ее у Вас ее нет, то Вы неверно установили Qt Creator (или Вы намерено не хотите создавать десктопные приложения). Та сборка Qt Creator официальная, которую я ставил (2.3), по умолчанию почему-то десктопные части не устанавливала.


4. В следующем окне снимите галочку с пункта "Создать форму".


5. В следующем окне можно ничего не менять. И жмем кнопку "Завершить".


Редактирование файла проекта


6. Отредактируем файл проекта (у нас это Example.pro):


И добавим к строчке "QT += core gui" слово "declarative". В итоге получим строчку:

QT       += core gui declarative


Создание QML проекта

7. По папке с проектом в Qt Creator щелкаем правой кнопкой и идем к пункту "Добавить новый..."


8. Выбираем слева "QML", а справа "Файл QML".


9. Назовем его "main".


10. Следующее окно без изменений.


11. В результате получим файл "main.qml" с текстом:

import QtQuick 1.0

Rectangle {
    width: 100
    height: 62
}


Создаем файл ресурсов

12. По папке с проектом в Qt Creator щелкаем правой кнопкой и идем к пункту "Добавить новый..."



13. Выбираем слева "Qt", а справа "Файл ресурсов Qt".


14. Назовем его "res".


15. Следующее окно без изменений.


В результате получим файд "res.qrc"

16. Добавим префикс. Для этого щелкнем по кнопке "Добавить", а там щелкнуть "Добавить префикс".


17. Измените текст префикса на "/".


18. Добавим наш QML файл. Для этого щелкнем по кнопке "Добавить", а там щелкнуть "Добавить файлы".


19. И выберем наш файл "main.qml". И файл добавится к ресурсам нашего приложения:


Если сейчас запустим наше приложение, то qml пока не увидим:


Редактирование исходников

Теперь займемся подключением qml, чтобы он заработал.

20. Перейдем к редактированию файла "mainwindow.h" (находится в заголовочных). Он имеет пока вид:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtGui/QMainWindow>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
};

#endif // MAINWINDOW_H


Поменяем его на такой вид:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtDeclarative/QDeclarativeView>
#include <QGraphicsObject>
#include <QtGui>
#include <QDeclarativeContext>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    QDeclarativeView *ui;
};

#endif // MAINWINDOW_H


Мы добавили #include <QtDeclarative/QDeclarativeView>, #include <QGraphicsObject> и др, добавили namespace, добавили ключевое слово explicit, и главное добавили QDeclarativeView *ui.

21. Теперь займемся редактированием файла mainwindow.cpp. Он имеет пока вид:

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
}

MainWindow::~MainWindow()
{

}


Поменяем на такой:

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    //Включаем наш QML
    ui = new QDeclarativeView;
    ui->setSource(QUrl("qrc:/main.qml"));
    setCentralWidget(ui);
    ui->setResizeMode(QDeclarativeView::SizeRootObjectToView);
}

MainWindow::~MainWindow()
{
    //Удаляем QML
    delete ui;
}


22. Запускаем наше приложение и получаем белое окно. Наш QML заработал.


Написание приложения


Теперь мы можем перейти к написанию непосредственно приложения, которое будет решать нашу задачу.

Построение интерфейса.

23. На данный момент main.qml выглядит так:

import QtQuick 1.0

Rectangle {
    width: 100
    height: 62
}




Отредактируем его, изменив главный прямоугольник-окно:

import QtQuick 1.0

//Главное окно
Rectangle {
    width: 300
    height: 300
    anchors.fill: parent

}


24. Добавим простейшую кнопку на нашу форму.

    //Кнопка
    Rectangle {
        id: button //Имя кнопки

        //Размещаем в центре
        x: parent.width / 2 - button.width / 2;
        y: parent.height / 2 - button.height / 2;

        //Размеры кнопки
        width: 100
        height: 30

        //Цвет кнопки
        color: "gray"

        //Текст кнопки
        Text {
            id: buttonLabel
            text: "Пуск"
            anchors.centerIn: parent;
        }

        //Действие мыши
        MouseArea {
            anchors.fill: parent
            id: mouseArea
        }
    }


В результате main.qml примет вид:

import QtQuick 1.0

Rectangle {
    width: 300
    height: 300
    anchors.fill: parent
    
    //Кнопка
    Rectangle {
        id: button //Имя кнопки

        //Размещаем в центре
        x: parent.width / 2 - button.width / 2;
        y: parent.height / 2 - button.height / 2;

        //Размеры кнопки
        width: 100
        height: 30

        //Цвет кнопки
        color: "gray"

        //Текст кнопки
        Text {
            id: buttonLabel
            text: "Пуск"
            anchors.centerIn: parent;
        }

        //Действие мыши
        MouseArea {
            anchors.fill: parent
            id: mouseArea
        }
    }
}


Если мы запустим приложение,

то получим следующее:


25. Добавим строку ввода, куда пользователь будет вводить информацию с именем textinput.

//Строка ввода
    Rectangle {
        id: textinputRect //Имя строки ввода

        //Размещаем ниже
        x: parent.width / 2 - button.width / 2;
        y: parent.height / 2 - button.height / 2+40;

        //Размеры строки ввода
        width: 100
        height: 18

        //цвет строки ввода
        color: "gray"

        TextInput {
            id: textinput
            objectName: "textinput"
            color: "#151515";
            selectionColor: "blue"
            font.pixelSize: 12;
            width: parent.width-4
            anchors.centerIn: parent
            focus: true
            text:"1"
            }
    }


В результате main.qml примет вид:

import QtQuick 1.0

Rectangle {
    width: 300
    height: 300
    anchors.fill: parent

    //Кнопка
    Rectangle {
        id: button //Имя кнопки

        //Размещаем в центре
        x: parent.width / 2 - button.width / 2;
        y: parent.height / 2 - button.height / 2;

        //Размеры кнопки
        width: 100
        height: 30

        //Цвет кнопки
        color: "gray"

        //Текст кнопки
        Text {
            id: buttonLabel
            text: "Пуск"
            anchors.centerIn: parent;
        }

        //Действие мыши
        MouseArea {
            anchors.fill: parent
            id: mouseArea
        }
    }
    
    //Строка ввода
        Rectangle {
            id: textinputRect //Имя строки ввода
    
            //Размещаем ниже
            x: parent.width / 2 - button.width / 2;
            y: parent.height / 2 - button.height / 2+40;
    
            //Размеры строки ввода
            width: 100
            height: 18
    
            //цвет строки ввода
            color: "gray"
    
            TextInput {
                id: textinput
                objectName: "textinput"
                color: "#151515";
                selectionColor: "blue"
                font.pixelSize: 12;
                width: parent.width-4
                anchors.centerIn: parent
                focus: true
                text:"1"
                }
        }
}

Обратите внимание на следующее:
  • Для того, чтобы мы смогли обращаться к строке ввода из С++ у нас кроме параметра id есть еще параметр objectName, который заключается в двойные кавычки.
  • Информация, которая нам потом будет нужна, содержится в параметре text.


При запуске получим следующее:


26. Добавим поле вывода, куда программа будет выводить ответ с именем memo.

    //Поле вывода
    Rectangle {
        id: memoRect //Имя поля вывода

        //Размещаем ниже
        x: parent.width / 2 - button.width / 2;
        y: parent.height / 2 - button.height / 2+70;

        //Размеры поле вывода
        width: 100
        height: 35

        //Цвет поля вывода
        color: "gray"

        TextEdit{
            id: memo
            objectName: "memo"
            wrapMode: TextEdit.Wrap
            width:parent.width;
            readOnly:true
        }
    }


В результате main.qml примет вид:

import QtQuick 1.0

Rectangle {
    width: 300
    height: 300
    anchors.fill: parent

    //Кнопка
    Rectangle {
        id: button //Имя кнопки

        //Размещаем в центре
        x: parent.width / 2 - button.width / 2;
        y: parent.height / 2 - button.height / 2;

        //Размеры кнопки
        width: 100
        height: 30

        //Цвет кнопки
        color: "gray"

        //Текст кнопки
        Text {
            id: buttonLabel
            text: "Пуск"
            anchors.centerIn: parent;
        }

        //Действие мыши
        MouseArea {
            anchors.fill: parent
            id: mouseArea
        }
    }

    //Строка ввода
        Rectangle {
            id: textinputRect //Имя строки ввода

            //Размещаем ниже
            x: parent.width / 2 - button.width / 2;
            y: parent.height / 2 - button.height / 2+40;

            //Размеры строки ввода
            width: 100
            height: 18

            //цвет строки ввода
            color: "gray"

            TextInput {
                id: textinput
                objectName: "textinput"
                color: "#151515";
                selectionColor: "blue"
                font.pixelSize: 12;
                width: parent.width-4
                anchors.centerIn: parent
                focus: true
                text:"1"
                }
        }

        //Поле вывода
        Rectangle {
            id: memoRect //Имя поля вывода

            //Размещаем ниже
            x: parent.width / 2 - button.width / 2;
            y: parent.height / 2 - button.height / 2+70;

            //Размеры поле вывода
            width: 100
            height: 35

            //Цвет поля вывода
            color: "gray"

            TextEdit{
                id: memo
                objectName: "memo"
                wrapMode: TextEdit.Wrap
                width:parent.width;
                readOnly:true
            }
        }
}


При запуске получим следующее:


Итак, мы описали интерфейс нашей программы.

C++ часть

27. При нажатии на кнопку пока ничего не происходит. Исправим это. Для начала установим взаимосвязь между QML моделью и C++ кодом. Для этого отредактируем файл mainwindow.cpp, а именно функцию MainWindow, добавив строчки:

 //Находим корневой элемент
    Root = ui->rootObject();
    //Соединяем C++ и QML, делая видимым функции С++ через элемент window
    ui->rootContext()->setContextProperty("window", this);


Получим следующее:

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    //Включаем наш QML
    ui = new QDeclarativeView;
    ui->setSource(QUrl("qrc:/main.qml"));
    setCentralWidget(ui);
    ui->setResizeMode(QDeclarativeView::SizeRootObjectToView);
    
    //Находим корневой элемент
    Root = ui->rootObject();
    //Соединяем C++ и QML, делая видимым функции С++ через элемент window
    ui->rootContext()->setContextProperty("window", this);
}

MainWindow::~MainWindow()
{
    //Удаляем QML
    delete ui;
}


28. В добавленном коде у нас присутствует необъявленная переменная Root . Через нее мы потом будем производить поиск всех других дочерних элементов. Объявим ее в mainwindow.h в классе в разделе private:

QObject *Root;//корневой элемент QML модели


В результате получим:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtDeclarative/QDeclarativeView>
#include <QGraphicsObject>
#include <QtGui>
#include <QDeclarativeContext>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    QDeclarativeView *ui;
    QObject *Root;//корневой элемент QML модели
};

#endif // MAINWINDOW_H


29. Пусть у нас кнопка из QML будет вызывать С++ функцию под произвольным именем FunctionC. Объявим ее в mainwindow.h в классе в разделе public:

Q_INVOKABLE void FunctionC();//Функция C++ вызываемая из QML


В результате получим:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtDeclarative/QDeclarativeView>
#include <QGraphicsObject>
#include <QtGui>
#include <QDeclarativeContext>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    
    Q_INVOKABLE void FunctionC();//Функция C++ вызываемая из QML

private:
    QDeclarativeView *ui;
    QObject *Root;//корневой элемент QML модели
};

#endif // MAINWINDOW_H


Обратите внимание на ключевое слово Q_INVOKABLE. Именно она делает видимой функцию для QML.

30. Теперь опишем нашу функцию в mainwindow.cpp:

void MainWindow::FunctionC()
{
    //Найдем строку ввода
    QObject* textinput = Root->findChild<QObject*>("textinput");
    
    //Найдем поле вывода 
    QObject* memo = Root->findChild<QObject*>("memo");
    
    QString str;//Создадим новую строковую переменную
    
    //Считаем информацию со строки ввода через свойство text
    str=(textinput->property("text")).toString();
    
    int a;
    a=str.toInt();//Переведем строку в число
    a++;//Добавим к числу 1
    
    QString str2;//Создадим еще одну строковую переменную
    str2=QString::number(a);//Переведем число в строку
    
    //Ну и наконец выведем в поле вывода нашу информацию
    memo->setProperty("text", str+"+1="+str2);
}


31. Ну и наконец добавим нашу функцию в обработчике нашей кнопки QML в файле main.qml. Обработчик действий мыши сейчас выглядит так:

//Действие мыши
        MouseArea {
            anchors.fill: parent
            id: mouseArea
        }


Теперь же он станет таким:

        //Действие мыши
        MouseArea {
            anchors.fill: parent
            id: mouseArea
            //При нажатии вызвать фугкцию window.FunctionC()
            onClicked: window.FunctionC()
        }


В итоге получим:

import QtQuick 1.0

Rectangle {
    width: 300
    height: 300
    anchors.fill: parent

    //Кнопка
    Rectangle {
        id: button //Имя кнопки

        //Размещаем в центре
        x: parent.width / 2 - button.width / 2;
        y: parent.height / 2 - button.height / 2;

        //Размеры кнопки
        width: 100
        height: 30

        //Цвет кнопки
        color: "gray"

        //Текст кнопки
        Text {
            id: buttonLabel
            text: "Пуск"
            anchors.centerIn: parent;
        }

        //Действие мыши
        MouseArea {
            anchors.fill: parent
            id: mouseArea
            //При нажатии вызвать фугкцию window.FunctionC()
            onClicked: window.FunctionC()
        }
    }

    //Строка ввода
        Rectangle {
            id: textinputRect //Имя строки ввода

            //Размещаем ниже
            x: parent.width / 2 - button.width / 2;
            y: parent.height / 2 - button.height / 2+40;

            //Размеры строки ввода
            width: 100
            height: 18

            //цвет строки ввода
            color: "gray"

            TextInput {
                id: textinput
                objectName: "textinput"
                color: "#151515";
                selectionColor: "blue"
                font.pixelSize: 12;
                width: parent.width-4
                anchors.centerIn: parent
                focus: true
                text:"1"
                }
        }

        //Поле вывода
        Rectangle {
            id: memoRect //Имя поля вывода

            //Размещаем ниже
            x: parent.width / 2 - button.width / 2;
            y: parent.height / 2 - button.height / 2+70;

            //Размеры поле вывода
            width: 100
            height: 35

            //Цвет поля вывода
            color: "gray"

            TextEdit{
                id: memo
                objectName: "memo"
                wrapMode: TextEdit.Wrap
                width:parent.width;
                readOnly:true
            }
        }
}


Обратите внимание на то, что функцию вызываем через window.

Вот и всё! Теперь запускаем программу и нажимаем на кнопку. Если Вы всё сделали правильно и я не допустил ошибок, то Вы увидете:

null

Ссылка на исходники: Скачать.
Ссылка на исполняемый файл: Скачать.
Сергиенко Антон @Harrix
карма
43,0
рейтинг 0,0
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (75)

  • +1
    Насчёт отсутствия примеров — Вы зря. Вот Вам Qt Developer Guides. Там отличный туторил по Qt Quick Application Developer Guide for Desktop. Так есть и по Programming with Qt Quick for Symbian and MeeGo Harmattan Devices.
    • +1
      Не нашел там описания взаимодействия QML и С++. Подробного описания начальных шагов тоже. Эта статья для самых новичков в этой среде — для тех, которые никогда Qt в глаза не видели, а программировали в других средах. И они, установив Qt Creator, не понимают, как что-то создать рабочее. При этом я ничего не говорю про уроки самого QML. Информации по этой области много.
      • +2
        Я не то чтобы имею что-то особо против этого примера. Пример хороший. Только вот идеологически он немного неправильный. Дело в том, что тут типичный пример где QML это frontend, а в C++ мы имеем backend и даже больше я скажу, что оно стоит того, чтобы использовать MVC где QML будет viewer, а в C++ классах будут располагаться controller и model, а общение между ними будет идти через сигналы и слоты.

        И в первую очередь сигналы должен подавать фронтенд бекенду и в обратную сторону backend должен бы отдавать только сигналы с какими-то параметрами фронтенду, а не напрямую управлять им, как это сделано у вас.

        Т.е., в конечном счете должно быть не memo->setProperty(«text», str+"+1="+str2) скажем, а emit memoText(value) и контроллеру уже должно быть пофиг как фронтенд распорядится тем, что ему дали… а вот общение контроллера и модели — тут да, тут имеет смысл прямые вызовы функций, но и то только иногда.
      • +3
        На мой взгляд вы пошли немного не с той стороны, нужно не QML встраивать в с++, а наоборот, на с++ делается как бы API будущей программы, а на QML+JS пишется весь GUI, который дергает c++ API, в основном это как правило различные модели да функции работы с базой и логикой. Код получается на порядок проще и чище.
        Вместо вот такого onClicked: window.FunctionC()
  • 0
    Бросился в глаза у Вас, следующий участок кода:

    Rectangle {
    id: button //Имя кнопки
    //Размещаем в центре
    x: parent.width / 2 - button.width / 2;
    y: parent.height / 2 - button.height / 2;


    Это можно сделать гораздо удобнее. Вот пример:

    Rectangle {
    width: 200
    height: 300
    color: "Red"
    Rectangle {
    width: 50
    height: 60
    color: "Blue"
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.verticalCenter: parent.verticalCenter
    }
    }

    Синий прямоугольник всегда будет по центру у меня. Посмотрите по очень важное свойво anchors. Например, тут.
    • 0
      Спасибо!
  • +2
    Ох блин, опять новички жить учат.
    Ну ок, ответьте мне пожалуйста на такие вопросы (я тоже новичок):

    Та сборка Qt Creator официальная, которую я ставил (2.3), по умолчанию почему-то десктопные части не устанавливала.

    Странно это, как они забыли в официальную сборку IDE(!) положить библиотеку и компилятор, совсем глупые наверное, хотя я где-то читал, что IDE != библиотека + компилятор + редактор и все нужно ставить отдельно или использовать QtSDK, подскажите, прав ли я?

    Мы добавили #include <QtDeclarative/QDeclarativeView>, #include и др, добавили namespace, добавили ключевое слово explicit, и главное добавили QDeclarativeView *ui.
    А зачем мы все это добавили, а если не добавить слово explicit, работать не будет? А без namespace?

            x: parent.width / 2 - button.width / 2;
            y: parent.height / 2 - button.height / 2;
    

    Ох как сложно, а мне рассказывали, что в QML есть какие-то лайоуты c которыми так удобно элементы расставлять. Обманывали наверное.

    Обратите внимание на ключевое слово Q_INVOKABLE.

    Я открыл стандарт С++ и не нашел там такого ключевого слова, где вы его взяли, а без него нельзя обойтись?

    Впрочем ладно пока хватит вопросов.
    • +2
      Q_INVOKABLE
      Q_PROPERTY

      и ряд других макроопределений это ключевые слова для прекомпилятора от Qt, который на основании этих меток строит метаобъектную систему. Подробнее в документации: doc.crossplatform.ru/qt/4.6.x/moc.html
      • +1
        То есть все-таки это макросы а не ключевые слова?
        Ну и конечно, мне было бы интересно послушать ответ автора статьи, в том числе и на вопрос, а нельзя ли обойтись без Q_INVOKABLE
        • +1
          Можно, сделать эти методы слотами.
          Основное отличие слота от метода помеченного как Q_INVOKABLE это то, что последний нельзя связать с сигналом.
          • +3
            Правда правда нельзя??? А если попробовать? ;)
            • +2
              Грешен, функционально идентичны, различие только семантическое.
              Но все же, ИМХО, без острой необходимости все равно лучше не связывать =).
          • –1
            Эм. Q_INVOKABLE возвращает значение, а вот со слота его стрясти проблематично.
            • +1
              Если объявить слот не void'ом и вызывать его как простой метод то он прекрасно вернет значение, равно как если такой слот дернуть из QML как метод он также прекрасно вернет значение.
              • 0
                Да? А почему когда я пытался из яваскрипта стрясти со слота возвращаемое значение мне упорно возвращали undefined?
                • 0
                  Это было из вебкита, но суть не меняется.
                  • 0
                    Меняется
                • +1
                  В QtScript оно всю жизнь замечательно работало. С этим как раз проблем нет.

                  Более того, можно любой слот вызывать по имени через QMetaObject::invoke и получить возвращаемое значение с использованием макроса Q_RETURN_ARG
            • 0
              >Q_INVOKABLE возвращает значение, а вот со слота его стрясти проблематично.

              Да ладно? И что, вы хотите сказать, что я не могу вызвать слот как обычный метод и получить от него результат? Подумайте ещё раз :)

              На самом деле даже через сигнал можно получить возвращаемое значение слота и присвоить его переменной. Просто пишем
              int value = emit someSignal();
              

              Другой вопрос, что делать это крайне нежелательно, т.к. сигнал может быть привязан к нескольким слотам, очерёдность вызова которых заранее неизвестна (вовсе необязательно, что они будут вызываться в порядке привязки сигналов), поэтому неизвестно, какое же именно значение будет присвоено.
              Ну или сигнал может быть не привязан ни к чему вообще.
        • 0
          Можно делать и слотами, а можно и так.
        • 0
          >Ну и конечно, мне было бы интересно послушать ответ автора статьи, в том числе и на вопрос, а нельзя ли обойтись без Q_INVOKABLE

          Для того, чтобы метод можно было вызывать из QML, он должен быть зарегистрирован в мета-системе Qt, что достигается либо через макрос Q_INVOKABLE, либо через объявление метода слотом.
        • 0
          Это не просто макросы в понимании C++. Их анализирует не компилятор а moc
    • 0
      По умочланию действительно десктоп не ставится, точнее не ставится компилятор MinGW. Нужно в начале установки щелкнуть малоприметную галочку «custom install» (или как-то так) и там добавить MinGW. Я тоже долго недоумевал, почему у меня на одном компе доступны десктопные проекты а на другом нет, хотя дистрибутив один и тот же:)
      • 0
        Верно!
    • 0
      Много вопросов. Постараюсь ответить на все.
      Странно это, как они забыли в официальную сборку IDE(!) положить библиотеку и компилятор, совсем глупые наверное

      Я не говорил, что они забыли положить библиотеку и компилятор. Просто при установке, как верно отметил NeoCode, нужно поставить галочку, чтобы установились части для создания десктопных приложений. Если всё ставить по умолчанию, то вариантов создания приложения для десктопа не будет.

      Мы добавили #include <QtDeclarative/QDeclarativeView>, #include и др… А зачем мы все это добавили

      Это требуется для того, чтобы связать QML и С++. Вполне возможно, что есть и другие способы, но в этом нужны эти модули.

      , добавили namespace
      Здесь соглашусь с Вами. Можно обойтись и без этого.

      главное добавили QDeclarativeView *ui.
      Ну без этого мы не подключим этим способом qml.

      Обманывали наверное.
      Статья не ставила своей целью показать красивости и основные приемы QML. Для этого существуют множество статей. Интерфейс был не важен, а была поставлена четко задача, которая и решалась.
      • +1
        Ошибся с оформлением цитат.
    • 0
      >А зачем мы все это добавили, а если не добавить слово explicit, работать не будет?

      Работать, разумеется, будет. Назначение explicit стоит вообще в стороне рассматриваемой проблемы. Его нужно указывать тогда, когда мы хотим запретить неявный вызов конструктора. Поясню лучше на примере:

      #include <iostream>
      
      class A {
      public:
      	A(int a) { _a = a; }
      private:
      	int _a;
      };
      
      class B {
      public:
      	explicit B(int b) { _b = b; }
      private:
      	int _b;
      };
      
      int main(int argc, char* argv[]) {
      	A a1(1); // ok - вызывается конструктор
      	A a2 = 2; // ok - неявно вызывается конструктор (нет, не оператор копирования, как часто думают)
      	
      	B b1(1); // ok - вызывается конструктор
      	B b2 = 2; // compiler error - попытка неявного вызова конструктора, помеченного как explicit
      
      	return 0;
      }
      
    • 0
      Это Visual Studio way )
  • +17
    > красивая и радует глаз

    >
    image


    facepalm.ui
    • 0
      По красивостям QML существует множество других статей. Цель этой статьи было показать пример связки.
  • 0
    «Нигде в сети не нашел примера «для чайников» (наверно плохо искал)»

    Можно было на Хабре попробовать ;)
    habrahabr.ru/blogs/qt_software/122046/
    • 0
      Я видел этот пример. Честно пытался несколько раз повторить его. Ни разу не получилось. Ошибки вылазят.
  • +6
    Простите, но что это за херня? Я не буду тонко троллить как «некоторые». Я так скажу.

    1. Нахрена нужен Widgets проект? Почему мы не стали делать quick проект?
    2. Зачем нам QMainWindow?
    3. Зачем нам ресурсы? Вернее они конечно нужны, но нафига их выставлять как непреложную истину? Для подобных хауту и различных тестов (да и в некоторых приложениях) можно обойтись без них
    4. Зачем так страшно искать qml объекты в плюсах? нельзя было сделать через сигнал-слот? То есть вызывается метод (хотя это тоже можно сделать через сигнал-слот, но бог с ним, пусть будет invoke напрямую) с параметром, в котором лежит текущее значение инпута. Что-то то там делается и испускается сигнал с нужным значением memo, который ловится в qml. Ведь так гораздо приятнее выглядит и удобнее потом править если что.
    5. Ну и да. хауту по кумлю даже на хабре уже вполне приличное количество. Про внешний интернет я вообще молчу
    • +1
      1. вначале искал этот способ через quick. Но опять так и не нашел способа взаимодействия с С++. Скорее всего плохо искал. Но не нашел. По крупицам собрал рассмотренный в статье пример. Буду рад, если покажете вариант, как решить поставленную в начале статьи задачу через quick проект.
      2. А как иначе?
      3. как минимум нужно увидеть qml файл. Можно и по другому, но ресурсы потом всё равно пригодятся для рисунков и др.
      4. Покажите, пожалуйста, пример.
      5. Про QML я ничего не говорю. А вот про взаимосвзяь QML и С++ для новичков нет. Точнее есть, но ни один из вариантов у меня по тем или иным причинам не заработал. Или вообще не запускается (всё перепроверялось на несколько раз) или не всю приводится и откуда то в коде возникает переменная, о которой до этого ничего не говорилось. Если бы получилось, то этой статьи не было. Возможно я просто тупой.
      • +2
        1. Ну дак через qmlRegisterType, через проперти контекста и прочее можно устроить взамоидействие. В чем проблема то? Создать еще один класс — наследник qobject?
        2. Ну например можно было в качестве топ левела выставить сам QDeclarativeView
        3. Его можно увидеть из самой файловой системы через относительный путь. Для подобного хауту этого способа за глаза хватит
        4. Пример чего? Отловки плюсового сигнала в кумле? Ищите в ассистанте элемент Connections кумльный
        5. В ассистанте есть очень хорошие статьи на тему взаимодействия
  • –5
    Есть же православные .ui, зачем этот велосипед?
    • +2
      Если вы немного не в теме о готовящемся Qt5, то сядьте, выпейте рюмочку чая и читайте
      labs.qt.nokia.com/2011/05/09/thoughts-about-qt-5/
      Вкратце о GUI — QML теперь основной способ создания интерфейса, а QWidget — модуль в отдельной либе…
      • –6
        Ужас. Чем оно лучше виджетов? Что-бы 2 поля и кнопку написать, целая страница кода требуется.
        • 0
          Тем, что это даже не компоненты полноценные, а кирпичики. Из них можно собрать что угодно и любой сложности, с максимальной степенью кастомизации. У них планируется требования малые сделать к системе, чтобы можно было с легкостью на всяких кофеварках запускать и тд :)
          • –6
            >>Из них можно собрать что угодно и любой сложности, с максимальной степенью кастомизации.
            Так и запишем: свистоперделки.
            >>У них планируется требования малые сделать к системе
            Там же всё на векторной графике, так что совсем наоборот.
            • +2
              графические ускорители давно ставят куда ни попадя. Тот же raspberry pi за 25 баксов выдает около 1к фпс на qt5&qml
              • –7
                Стоп. Сначала вы говорите, что qml пилят под кофеварки, а теперь, что кофеварки под qml. В общем, ничего кроме свистоперделок вроде прозрачности и анимации в этом велосипеде нету.
                • +1
                  я? я вообще молчу, чо :D
                  Никто кофеварки под кумль не пилит. Я говорил про нынешние технические возможности, которые позволяют без проблем реализовать красивый и приятный (не как в посте, а действительно приятный) интерфейс без лишних затрат на разработку и поддержку этого интерфейса
                  • –2
                    Простите, перепутал. А оно уже умеет хотя-бы QPushButton, зависящий от QT-темы одной строчкой?
                    • +1
                      умеет. В десктопных компонентах
                    • +1
                      import QtDesktop 0.2
                      
                      Button {
                      text: qsTr("Click Me")
                      onClicked: foo.bar()
                      }
                      
            • 0
              «Свистоперделки» — нужная штука, можно шикарный GUI сделать, степень кастомизации и простота анимации на высоте! Технология шикарна!

              >> Там же всё на векторной графике, так что совсем наоборот.
              Почитайте про Scenegraph
              • –3
                >>«Свистоперделки» — нужная штука, можно шикарный GUI сделать, степень кастомизации и простота анимации на высоте! Технология шикарна!
                Стена там --->
                • +2
                  Да я с вами согласен, нативный Motif — лучший на все времена.

                  image
                  • –2
                    В том-то и дело, что приложение на виджетах в разных темах оформления будет выглядеть однородно. А qml продвигает совершенно противоположную идею быдлогуестроения, где каждое приложение имеет свой стиль и своё оформление. Вот вы-бы смогли работать в таком зоопарке?
                    • 0
                      Снова неверно — Desktop Components подхватывают стиль системы!
                      labs.qt.nokia.com/2011/03/10/qml-components-for-desktop/
                      • 0
                        И зачем, когда на qtgui это всё будет занимать в 2 раза меньше кода?
                        • +1
                          Да с Вами невозможно разговаривать, неужели дело только в длине кода?!

                          Попробуйте написать анимацию на C++ и на QML, почувствуете разницу!
                          А еще просто откройте для себя QtQuick 3d, ну просто (совсем совсем) никакого сравнения C++ кодом… Если уж вас так волнует его длина…
                          • 0
                            Анимация и 3d в системных приложениях не нужны. Роль гуя — удобное представление данных и элементов управления. Всё остальное для 13-летних девочек.
                            • +2
                              115-летний мальчик, ты бы хоть посмотрел на то как сейчас выглядят UI мобильных осей или последних десктопных осей (macosx 10.7, win7, kde4, gnome3, unity). А потом бы уже говорил. Ну очень толсто же
                              • +1
                                >>kde4, gnome3, unity
                                Цепляют тему gtk+ и qt
                                >>win7
                                цепляют тему винды
                                >>macosx
                                Не видел в живую, но, судя по скриншотам, там все приложения стилизованы одинаково.
                                А если вы про анимацию или 3d, то ни разу не видел этого ни в gtk+-, ни в qt- приложениях и это меня очень радует.
                                • 0
                                  Человек, остановись, признай свою неправоту, а не продолжай сам себя припирать к стенке. Иначе скоро выяснится, что ты и приложений на Qt не видел ни одного…
                                  • +1
                                    А что я неправильно-то сказал? Насколько я понял, ваш единственный аргумент в пользу qml — анимация и 3d. На что я привёл свою точку зрения:
                                    >>Роль гуя — удобное представление данных и элементов управления. А анимация только мешает восприятию данных и выбивается из общего стиля окружения.
                                    С чем конкретно вы не согласны?
                                    • 0
                                      анимация (ясен пень правильная и не навязчивая) облегчает восприятие данных. Делает его более естественным
                                • 0
                                  у меня тряпочки закончились чтобы жир с экрана стирать

                                  ты не видел анимаций в приложениях? Лол. Анимации везде используются сейчас. Истинное 3д да, не используется. Но шейдеры очень хороший инструмент для создания сложных анимаций
                                  • 0
                                    >>ты не видел анимаций в приложениях?
                                    Сложнее смены иконки при наведении или клике? Нет. И, повторюсь, рад этому. Долго искал на ютубе видео, где приложение стартует около 20-30 секунд, показывая юзеру всевозможные красивости, но, к сожалению, не нашёл. Так вот, если вы стремитесь к такому десктопу — пожалуйста. А я всё-же надеюсь на благоразумность qt-разработчиков.
                                    • +2
                                      слушай, тролль, а ты разницу между ненавязчивой естественной анимацией и 20-30 секундами вступительного ролика ваще чуешь? или нет?
                                      • –1
                                        Фу, как невежливо. У нас с вами разное видение современного десктопа, так-что предлагаю закончить спор, оставшись каждый при своём мнении. Это всё-равно, что спорить об искусстве. Для меня ненавязчивая анимация заканчивается на смене стиля при наведении мыши.
                                        • –1
                                          невежливо это троллить так толсто, как делаешь это ты. Я с трудом буквы твоего коммента через жир из монитора вижу
                                    • 0
                                      Парень, скажи это Стиву, царство ему небесное…
                                      • 0
                                        Это вы мне так тонко смерти пожелали? =)
                                        Стив умел делать деньги на хомячках. И делал он это отчасти из-за красивостей и анимаций, да.
                                        • +1
                                          Неужели Вы на что-то согласились…
                          • 0
                            не кормите троля
                            • 0
                              да ладно чо. Покормить иногда забавно
  • 0
    Так и не понял чем автору не понравилось сразу создать «приложение QtQuick» и почему он не заглянул в примеры, там есть пара замечательных примеров на тему Extending QML with C++.
    • 0
      Я не понял этих примеров. Точнее не понял как решить задачу, которую перед собой поставил здесь. Я туп.
  • +1
    Отличный пример! Спасибо! Неохота вечером после работы еще ковыряться в англоязычном материале!
    А люди, имеющие хороший опыт в разработке на Qt, прекрасно должны уметь читать не только код, но и заголовок. В котором русским по белому написано «QML и C++. Простой пример связки». Слово «Простой» тут с заглавной буквы даже написано)

    А если есть мнение, что хабр не место для простых примеров, то надо объяснить, что существуют вещи типа github или bitbucket, которые индексируются не хуже Хабра, и что их можно использовать в разных целях, даже для того чтоб поделиться опытом, пускай и небольшим. А если надоело объяснять такие простые истины, то спросите себя: «Мне не надоело угнетать новичка, который недавно в чем-то сложном для него разобрался?»

    Еще раз спасибо автору! Написал отличное дополнение к официальной документации и множеству примеров. Пишу без малейшего сарказма.
  • 0
    Огромное спасибо за поддержку!
    Вот тут переписанный пример для Qt Quick www.harrix.org/main/article.php?id=83
  • 0
    blog.harrix.org/?p=3108 — новая версия статьи. Данная устарела.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.