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

Пишем QtQuick компоненты. C++ модели в QML, вызов C++ кода из QML.

Запись от Dmitriy_M размещена 10.02.2013 в 18:20
Показов 14867 Комментарии 0

Появился Qt 5.0.1 с компилятором MinGW и начал потихонечку пробовать.

В этой записи будет рассматриваться Qt5, но так же упомяну как некоторые вещи делались в Qt4.
Как то мне потребовался компонент, для выбора/установке даты в приложение с тач-интерфейсом на Qt4, а готового календаря не оказалось.
Поэтому будем делать свой календарь

Как хотелось, что бы выглядело в коде
JavaScript
1
2
3
4
Calendar{
    month: 5
    year: 2014
}
Здесь вывод календаря на май месяц 2014 года.

Я не пошел по пути генерации компонентов и JavaScript, а использовал модели и view, для создания динамических свойств.

Описываем модель календаря.
Как оказалась, View элементы QML, будут с любой моделью работаться как со списком, поэтому наследуемся от QAbstractListModel.
Введем перечисление ролей, через которые будет идти обращение из QML к данным нашей модели:
C++ (Qt)
1
2
3
4
5
enum Roles
{
    Date = Qt::UserRole + 1,
    Month 
};
Модель будет хранить следующие данные:
C++ (Qt)
1
2
3
4
5
struct Record
{
   int day;  
   int month; 
};
month предназначен, для выделения ячейки другим цветом.

Дальше добавим свойства месяц и год, что бы календарь был настраиваемым из QML:
C++ (Qt)
1
2
Q_PROPERTY(int month READ month WRITE setMonth NOTIFY monthChanged)
Q_PROPERTY(int year READ year WRITE setYear NOTIFY yearChanged)
Добавим два метода, которые мы сможем вызывать из QML, что бы получать имя дня недели и имя месяца:
C++ (Qt)
1
2
Q_INVOKABLE QString shortDayName(int day)const;
Q_INVOKABLE QString longMonthName(int month)const;
Методы которые нужно переопределить:
C++ (Qt)
1
2
3
virtual int rowCount(const QModelIndex & parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
virtual QHash<int, QByteArray> roleNames() const;
В Qt4 был метод:
C++ (Qt)
1
void QAbstractItemModel::setRoleNames(const QHash<int, QByteArray> & roleNames) [protected]
Что позволял не переопределять roleNames

Полный вид класса такой:
Кликните здесь для просмотра всего текста

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
class CalendarModel : public QAbstractListModel
{
    Q_OBJECT
 
    /*!
     * \brief Роли модели
     */
    enum Roles
    {
        Date = Qt::UserRole + 1, //!< день
        Month                    //!< месяц
 
    };
 
    /*! свойство месяц */
    Q_PROPERTY(int month READ month WRITE setMonth NOTIFY monthChanged)
 
    /*! свойство гов */
    Q_PROPERTY(int year READ year WRITE setYear NOTIFY yearChanged)
 
    /*!
     * \brief запись хранимая в модели
     */
    struct Record
    {
        int day;   //!< день
        int month; //!< месяц
    };
 
public:
    explicit CalendarModel(QObject *parent = 0);
 
    /*!
     * \brief month получить месяц
     */
    int month()const;
 
    /*!
     * \brief setMonth установить месяц
     * \param month от 1 до 12
     */
    void setMonth(int month);
 
    /*!
     * \brief year получить год
     */
    int year()const;
 
    /*!
     * \brief setYear установить год
     * \param year
     */
    void setYear(int year);
 
    /*!
     * \brief получить короткое имя дня недели
     * \param day день недели от 1 до 7
     * Получение короткого названия дня недели.
     * 1 = "Mon"
     */
    Q_INVOKABLE QString shortDayName(int day)const;
 
    /*!
     * \brief получить длинное имя месяца
     * \param month месяц от 1 до 12
     */
    Q_INVOKABLE QString longMonthName(int month)const;
 
    virtual int rowCount(const QModelIndex & parent = QModelIndex()) const;
    virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
    virtual QHash<int, QByteArray> roleNames() const;
 
signals:
 
    /*!
     * \brief monthChanged
     * Оповещение изменения месяца
     */
    void monthChanged();
 
    /*!
     * \brief yearChanged
     * Оповещение изменения года
     */
    void yearChanged();
 
public slots:
 
    /*!
     * \brief updateModel обновление модели
     */
    void updateModel();
private:
 
    int month_; //!< месяц
    int year_;  //!< год
    QVector<Record> data_;//!< хранимые данные
    QHash<int, QByteArray> roles_;
    
};


Из реализации приведем пару интересных методов:
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
33
34
35
36
37
38
39
40
CalendarModel::CalendarModel(QObject *parent) :
    QAbstractListModel(parent)
{
 
    roles_[Date] = "date";
    roles_[Month] = "month";
 
    QDate curentDate = QDate::currentDate();
 
    month_ = curentDate.month();
    year_  = curentDate.year();
 
    updateModel();
}
QHash<int, QByteArray> CalendarModel::roleNames() const
{
    return roles_;
}
QString CalendarModel::shortDayName(int day)const
{
    return QDate::shortDayName(day);
}
 
 
QString CalendarModel::longMonthName(int month)const
{
    return QDate::longMonthName(month);
}
QVariant CalendarModel::data(const QModelIndex & index, int role ) const
{
    if(!index.isValid())
        return QVariant();
 
    switch (role)
    {
    case Date: return data_[index.row()].day;
    case Month: return data_[index.row()].month;
    default: return QVariant();
    }
}
Модель есть, теперь надо зарегистрировать среди типов QML
C++ (Qt)
1
qmlRegisterType<CalendarModel>("QmlExtension", 1, 0, "CalendarModel");
Здесь QmlExtension это где находится компонент, этот путь мы будем писать при импорте в QML. 1, 0 это версия, дальше имя, которое будет доступно в QML.

Теперь самое время написать внешний вид.
Тут все довольно просто:
JavaScript
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import QtQuick 2.0
import QmlExtension 1.0
 
Rectangle {
    width: 300
    height: 200
 
    border.width: 1
    border.color: "gray"
 
    property int headerHeight: 40
    property alias year: calModel.year
    property alias month: calModel.month
 
    CalendarModel{
        id: calModel
    }
 
    GridView{
        id:view
        anchors.left: parent.left
        anchors.right: parent.right
        height: parent.height
        width: parent.width
        model:calModel
 
        cellWidth: width / 7
        cellHeight: (height-headerHeight)/(count/7)
 
        interactive: false
 
        header:Item {
            height: headerHeight
            width: parent.width
            Text {
                width: parent.width
                horizontalAlignment:  Text.AlignHCenter
 
                text: calModel.longMonthName(calModel.month);
                font.family: "Verdana"
                font.bold: true
                font.pointSize: 13
            }
            Row{
                height: parent.height/2
 
                anchors.left: parent.left;
                anchors.right: parent.right
                anchors.bottom: parent.bottom
                Repeater{
                    model:7
                    Text {
                        width: view.cellWidth
                        height: parent.height
 
                        horizontalAlignment:  Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
 
                        text: calModel.shortDayName(index+1)
                        font.family: "Verdana"
                        font.bold: true
                    }
                }
            }
        }
 
 
 
        delegate: Rectangle{
            height:view.cellHeight
            width: view.cellWidth
            border.width: 1
            border.color: "gray"
 
            Rectangle{
                height: parent.height
                width: parent.width
                color: calModel.month != month ? "lightgray":"white"
                opacity: 0.5
            }
 
 
            Text{
                anchors.centerIn: parent
                text:date
 
                font.family: "Verdana"
                font.bold: true
 
            }
        }
    }
}
Обращаю внимание на вторую строчку:
import QmlExtension 1.0
Здесь происходит загрузка нашего компонента.

Календарь на месяц это здорово, но давайте сделаем на целый год:
JavaScript
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
import QtQuick 2.0
import QmlExtension 1.0
 
Flickable{
     contentWidth: calendarGrid.width;
     contentHeight: calendarGrid.height
     width: 900
     height: 500
 
     Grid{
 
         id: calendarGrid
         columns : 3
         rows: 4
         spacing:20
 
         Repeater{
             model:12
 
 
             Calendar{
                 month: index+1
 
             }
         }
     }
}
Все здорово, но неудобно, хочется все это было доступно в qmlscene.
Поэтому напишем плагин.
Выглядит плагин так:
C++ (Qt)
1
2
3
4
5
6
7
8
class QMLExtensionPlugin : public QQmlExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
    
public:
    void registerTypes(const char *uri);
};
В Qt4 для этого предназначен QDeclarativeExtensionPlugin.
Реализация простая:
C++ (Qt)
1
2
3
4
void QMLExtensionPlugin::registerTypes(const char *uri)
{
    qmlRegisterType<CalendarModel>(uri, 1, 0, "CalendarModel");
}
Дальше пишем qmldir файл описывающий из чего состоит этот компонент
C
1
2
3
4
module QmlExtension
Calendar 1.0 Calendar.qml
YearCalendar 1.0 YearCalendar.qml
plugin qmlextension
В Qt4 плагины располагаются в подкаталоге imports, в Qt5 подкаталоге qml.
При распространения приложения, кладем плагин рядом и устанавливаем пути поиска
В Qt5
C++ (Qt)
1
void QQmlEngine::addPluginPath(const QString & path)
В Qt4
C++ (Qt)
1
void QDeclarativeEngine::addPluginPath ( const QString & path )
Исходные тексты лежат на Google Code
Миниатюры
Нажмите на изображение для увеличения
Название: CalendarMay.png
Просмотров: 1260
Размер:	26.4 Кб
ID:	1719   Нажмите на изображение для увеличения
Название: YearCalendar.png
Просмотров: 1087
Размер:	98.8 Кб
ID:	1720  
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Мысли в слух
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. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru