Evgenii Legotckoi
Evgenii Legotckoi22. Oktober 2015 12:40

QML - Lektion 006. Benutzerdefinierter Kalender in Qt QML oder Qt QML Android

In dieser Lektion möchte ich darüber sprechen, wie Sie das Erscheinungsbild des Objekts Calendar in Qt Qml anpassen können. Korrigieren Sie beispielsweise Farben, Schriftarten und passen Sie sie auch schön in das Dialogfeld zur Auswahl eines Datums ein. Lassen Sie uns daher entscheiden, wie unsere Anwendung funktionieren und wie sie aussehen soll:

  1. Das Hauptfenster der Anwendung enthält eine Standardschaltfläche, die das Datum anzeigt (obwohl Sie es auch [anpassen] können, wenn Sie möchten (https://evileg.com/ru/post/64/));
  2. Durch Klicken auf die Schaltfläche öffnet sich ein Dialogfenster mit dem Kalender und zwei Schaltflächen ("Ok" und "Abbrechen"). Der Kalender wird auf das Datum eingestellt, das auf der Schaltfläche angegeben wurde;
  3. Wenn Sie auf die Schaltfläche "Abbrechen" klicken, passiert nichts, und das Dialogfeld wird einfach geschlossen.
  4. Durch Klicken auf die Schaltfläche „Ok“ wird das Dialogfeld geschlossen und die Schaltfläche des Hauptfensters zeigt das Datum an, das im Kalender ausgewählt wurde.

Ich glaube, Sie haben bereits bemerkt, dass das Anpassen der Anwendungsschnittstelle in Qt QML sowohl für Desktop -Versionen als auch für Android dasselbe ist. Andernfalls würde die Entwicklung unter Qt nicht funktionieren als plattformübergreifend angesehen. Daher werde ich nicht zu sehr auf den Unterschied zwischen der Einstellung der Dialogfeldanzeige für die Desktop -Version und die Android -Version eingehen. Ich habe diesen Punkt im Tutorial zum Erstellen eines benutzerdefinierten Dialogfelds erklärt.


Projektstruktur für benutzerdefinierten Kalender

Zur Demonstration des Beispiels wurde ein neues Projekt mit folgender Struktur angelegt:

  • QmlCalendarCustom.pro - Projektprofil;
  • main.cpp - Hauptquellcodedatei;
  • main.qml - Haupt-QML-Schnittstellendatei;
  • left_arrow.png - linker Pfeil nicht gedrückt;
  • left_arrow_disable.png - linker Pfeil gedrückt;
  • right_arrow.png - Rechtspfeil nicht gedrückt;
  • right_arrow_disable.png - Rechtspfeil gedrückt.

Pfeile

Ich verwende die folgenden Bilder, um das Scrollen der Monate im Kalender anzupassen.

main.cpp

Diese Datei wird standardmäßig erstellt, aber ich werde ihren Programmcode angeben, damit es keine Verwirrung gibt.

#include <QApplication>
#include <QQmlApplicationEngine>

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

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

    return app.exec();
}

main.qml

Aber wir werden die ganze Schande in dieser Datei erstellen. Darin erstellen wir einen benutzerdefinierten Kalender , der das Datum auf der Schaltfläche festlegt.

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.2

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

    /* Создадим переменную для хранения даты, чтобы не заморачиваться
     * с конвертацией типов
     * */
    property var tempDate: new Date();

    Button {
        id: button
        // Устанавливаем текущую дату при запуске приложения на кнопку
        text: Qt.formatDate(tempDate, "dd.MM.yyyy");
        anchors.centerIn: parent // Центруем кнопку в окне

        // По клику на кнопку запускаем диалоговое окно черз кастомную функцию
        onClicked: dialogCalendar.show(tempDate)

    }

    Dialog {
        id: dialogCalendar
        // Задаём размеры диалогового окна
        width: 250
        height: 300

        // Создаем контент диалогового окна
        contentItem: Rectangle {
            id: dialogRect
            color: "#f7f7f7"

            // Первым идёт кастомный календарь
            Calendar {
                id: calendar
                // Размещаем его в верхней части диалога и растягиваем по ширине
                anchors.top: parent.top
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.bottom: row.top

                // Стилизуем Календарь
                style: CalendarStyle {

                    // Стилизуем navigationBar
                    navigationBar: Rectangle {
                        /* Он будет состоять из прямоугольника,
                         * в котором будет располагаться две кнопки и label
                         * */
                        height: 48
                        color: "#f7f7f7"

                        /* Горизонтальный разделитель,
                         * который отделяет navigationBar от поля с  числами
                         * */
                        Rectangle {
                            color: "#d7d7d7"
                            height: 1
                            width: parent.width
                            anchors.bottom: parent.bottom
                        }

                        // Кнопка промотки месяцев назад
                        Button {
                            id: previousMonth
                            width: parent.height - 8
                            height: width
                            anchors.verticalCenter: parent.verticalCenter
                            anchors.left: parent.left
                            anchors.leftMargin: 8

                            /* По клику по кнопке вызываем функцию
                             * календаря, которая отматывает месяц назад
                             * */
                            onClicked: control.showPreviousMonth()

                            // Стилизуем кнопку
                            style: ButtonStyle {
                                background: Rectangle {
                                    // Окрашиваем фон кнопки
                                    color: "#f7f7f7"
                                    /* И помещаем изображение, у которго будет
                                     * два источника файлов в зависимости от того
                                     * нажата кнопка или нет
                                     */
                                    Image {
                                        source: control.pressed ? "left_arrow_disable.png" : "left_arrow.png"
                                        width: parent.height - 8
                                        height: width
                                    }
                                }
                            }
                        }

                        // Помещаем стилизованный label
                        Label {
                            id: dateText
                            /* Забираем данные из title календаря,
                             * который в данном случае не будет виден
                             * и будет заменён данным label
                             */
                            text: styleData.title
                            color:  "#34aadc"
                            elide: Text.ElideRight
                            horizontalAlignment: Text.AlignHCenter
                            font.pixelSize: 16
                            anchors.verticalCenter: parent.verticalCenter
                            anchors.left: previousMonth.right
                            anchors.leftMargin: 2
                            anchors.right: nextMonth.left
                            anchors.rightMargin: 2
                        }

                        // Кнопка промотки месяцев вперёд
                        Button {
                            id: nextMonth
                            width: parent.height - 8
                            height: width
                            anchors.verticalCenter: parent.verticalCenter
                            anchors.right: parent.right

                            /* По клику по кнопке вызываем функцию
                             * календаря, которая отматывает месяц назад
                             * */
                            onClicked: control.showNextMonth()

                             // Стилизуем кнопку
                            style: ButtonStyle {
                                // Окрашиваем фон кнопки
                                background: Rectangle {
                                    color: "#f7f7f7"
                                    /* И помещаем изображение, у которго будет
                                     * два источника файлов в зависимости от того
                                     * нажата кнопка или нет
                                     */
                                    Image {
                                        source: control.pressed ? "right_arrow_disable.png" : "right_arrow.png"
                                        width: parent.height - 8
                                        height: width
                                    }
                                }
                            }
                        }
                    }


                    // Стилизуем отображением квадратиков с числами месяца
                    dayDelegate: Rectangle {
                        anchors.fill: parent
                        anchors.margins: styleData.selected ? -1 : 0
                        // Определяем цвет в зависимости от того, выбрана дата или нет
                        color: styleData.date !== undefined && styleData.selected ? selectedDateColor : "transparent"

                        // Задаём предопределённые переменные с цветами, доступные только для чтения
                        readonly property color sameMonthDateTextColor: "#444"
                        readonly property color selectedDateColor: "#34aadc"
                        readonly property color selectedDateTextColor: "white"
                        readonly property color differentMonthDateTextColor: "#bbb"
                        readonly property color invalidDateColor: "#dddddd"

                        // Помещаем Label для отображения числа
                        Label {
                            id: dayDelegateText
                            text: styleData.date.getDate() // Устанавливаем число в текущий квадрат
                            anchors.centerIn: parent
                            horizontalAlignment: Text.AlignRight
                            font.pixelSize: 10

                            // Установка цвета
                            color: {
                                var theColor = invalidDateColor; // Устанавливаем невалидный цвет текста
                                if (styleData.valid) {
                                    /* Определяем цвет текста в зависимости от того
                                     * относится ли дата к выбранному месяцу или нет
                                     * */
                                    theColor = styleData.visibleMonth ? sameMonthDateTextColor : differentMonthDateTextColor;
                                    if (styleData.selected)
                                        // Перекрашиваем цвет текста, если выбрана данная дата в календаре
                                        theColor = selectedDateTextColor;
                                }
                                theColor;
                            }
                        }
                    }
                }
            }

            // Делаем панель с кнопками
            Row {
                id: row
                height: 48
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.bottom: parent.bottom

                // Кнопка для закрытия диалога
                Button {
                    id: dialogButtonCalCancel
                    anchors.top: parent.top
                    anchors.bottom: parent.bottom
                    width: parent.width / 2 - 1

                    style: ButtonStyle {
                        background: Rectangle {
                            color: control.pressed ? "#d7d7d7" : "#f7f7f7"
                            border.width: 0
                        }

                        label: Text {
                            text: qsTr("Cancel")
                            font.pixelSize: 14
                            color: "#34aadc"
                            verticalAlignment: Text.AlignVCenter
                            horizontalAlignment: Text.AlignHCenter
                        }
                    }
                    // По нажатию на кнопку - просто закрываем диалог
                    onClicked: dialogCalendar.close()
                }

                // Вертикальный разделитель между кнопками
                Rectangle {
                    id: dividerVertical
                    width: 2
                    anchors.top: parent.top
                    anchors.bottom: parent.bottom
                    color: "#d7d7d7"
                }

                // Кнопка подтверждения выбранной даты
                Button {
                    id: dialogButtonCalOk
                    anchors.top: parent.top
                    anchors.bottom: parent.bottom
                    width: parent.width / 2 - 1

                    style: ButtonStyle {
                        background: Rectangle {
                            color: control.pressed ? "#d7d7d7" : "#f7f7f7"
                            border.width: 0
                        }

                        label: Text {
                            text: qsTr("Ok")
                            font.pixelSize: 14
                            color: "#34aadc"
                            verticalAlignment: Text.AlignVCenter
                            horizontalAlignment: Text.AlignHCenter
                        }
                    }

                    /* По клику по кнопке сохраняем выбранную дату во временную переменную
                     * и помещаем эту дату на кнопку в главном окне,
                     * после чего закрываем диалог
                     */
                    onClicked: {
                        tempDate = calendar.selectedDate
                        button.text = Qt.formatDate(tempDate, "dd.MM.yyyy");
                        dialogCalendar.close();
                    }
                }
            }
        }

        /* Данная функция необходима для того, чтобы
         * установить дату с кнопки в календарь,
         * иначе календарь откроется с текущей датой
         */
        function show(x){
            calendar.selectedDate = x
            dialogCalendar.open()
        }
    }
}

Insgesamt

Als Ergebnis sollten Sie eine Anwendung mit dem folgenden Dialogfeld haben, in dem sich ein benutzerdefinierter Kalender befindet. Auch im Video-Tutorial gibt es eine Demonstration der Anwendung mit Kommentaren zum Programmcode.

Videoanleitung

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

M
  • 12. Oktober 2017 15:13

Все очень круто, больше спасибо.
Подскажите пжлст что такое styleData?
Это какой то объект из dialogCalendar
Если я захочу другое отображение колендаря, мне нужно будет перегружать функции в новом классе?

Evgenii Legotckoi
  • 13. Oktober 2017 03:13

Добрый день!
Ага, это внутренний объект стилей.

И да, понадобится перегружать. А вообще посмотрите ещё календарь из Quick.Controls 2.0, поскольку этот пример из Quick.Controls 1.4 - он устаревший.
А в новых контролах совсем иначе сделано, там вроде бы вместо стилей делегаты используются, всё несколько проще. Будут вопросы, на форуме спрашивайте по новым контролом, что смогу, подскажу.
M
  • 13. Oktober 2017 06:20

Спасибо)

U
  • 6. Januar 2020 09:35
  • (bearbeitet)

Привет. Вопрос именно по старой версии календаря(controls 1.4).
1. Подскажите как календарь определяет выбранный день.
2. В styleData.selected возвращается true если дата выбрана, но я так и не нашёл как вручную выбирается дата...
3. ...если работать с onClicked в области делегата, то автоматический механизм выбора ячейки календаря перестаёт работать. Как быть?
Подытожу. Без onClicked подсветка выбранного дня работает, но если мне нужно производить какие нибудь действия по нажатии на ячейку через onClicked, то всё ломается. Это же касается и onPressed, onReleased и пр.
П.С. Пробовал в onClicked менять градиент выбранного дня - получилось, но мозгов допилить изменение градиента остальных дней не хватает.

U
  • 7. Januar 2020 08:57
  • (bearbeitet)

Отвечу сам себе.
Чтоб подсветка ячейки менялась при нажатии применил следующее:

MouseArea{
    anchors.fill: daydel//id делегата дня
    onClicked: {
    //curDate, curD, curM, curY - стринговые переменные объявленные в коренном объекте(property string curDate)
        curDate = styleData.date.toLocaleDateString("dd.MM.yyyy")
        curD = curDate.slice(0,2)//вернет день дд
        curM = curDate.slice(3,5)//вернет месяц мм
        curY = curDate.slice(-4)//вернет год гггг
        calendar.selectedDate = curY+"-"+curM+"-"+curD
    }
}

Но пока что имеются проблемы с правильным переходом на предыдущий/следующий месяц и получением правильной даты при нажатии на дату не находящуюся в текущем месяце.

U
  • 8. Januar 2020 06:52
  • (bearbeitet)

.

Evgenii Legotckoi
  • 9. Januar 2020 16:36

Вы перекрываете события этим MouseArea, попробуйте пропихнуть всё дальше включив следующее свойство

MouseArea {
    propagateComposedEvents: true
}

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 14:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 18:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr9. Februar 2024 02:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 18:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 10:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 22:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 16:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 11:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken