0

I found the calendar implemented using QML. I want to embed it in my program. I have the main window of the program ui-form. Clicking on "line Edith" should open a calendar implemented with QML? How to do it? And how do I transfer the date from the calendar to "Line Edit"? enter image description here This is the code for popupCalendar.qml:

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

Item {
    property var tempDate: new Date();

    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()
         }
     }
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Ivan Triumphov
  • 155
  • 1
  • 11
  • I don't know of a straightforward `signal` to detect clicks inside `QLineEdit`, but you can use `returnpressed` signal when press _Enter_ key inside focused `QLineEdit` widget. – Mohammad Kanan Mar 19 '18 at 18:28

1 Answers1

2

The problem is divided into 2 parts:

1. Detection of the click in QLineEdit.

to detect the mouse click you must use eventFilter:

   ui->lineEdit->installEventFilter(this);

....

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == ui->lineEdit){
        if(event->type() == QEvent::MouseButtonPress){
             // clicked 
             showCalendar();
        }
    }
    return QMainWindow::eventFilter(watched, event);
}

2. Show the Dialog and get the selected date:

The first task is to remove the Item {}, and only keep the Dialog, and adding the selectedDate property that will be the selected date.

popularCalendar.qml

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

Dialog {
    id: dialogCalendar
    property date selectedDate: new Date()
    // Задаём размеры диалогового окна
    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: {
                    dialogCalendar.selectedDate = calendar.selectedDate
                    dialogCalendar.close()
                }
            }
        }
    }

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

and then load and create that component using QQmlComponent.

*.h

class MainWindow : public QMainWindow
{
    ...
private:
    void showCalendar();
    Q_SLOT void onSelectedDate();

    QObject *dialog = Q_NULLPTR;
    QQmlEngine *engine;
    QQmlComponent *component;
    ....
};

*.cpp

// constructor
engine = new QQmlEngine(this);
component = new QQmlComponent(engine, QUrl(QStringLiteral("qrc:/popupCalendar.qml")), this);

and then using a previous answer with the help of QMetaObject we connect the signal associated with the property selectedDate with a slot, in addition we call the show function implemented in the QML.

void MainWindow::showCalendar()
{
    if(dialog == Q_NULLPTR){
        dialog = component->create();
        int index = dialog->metaObject()->indexOfProperty("selectedDate");
        const QMetaProperty property = dialog->metaObject()->property(index);
        if (property.hasNotifySignal()){
            const QMetaMethod s = property.notifySignal();
            QString sig = QString("2%1").arg(QString(s.methodSignature()));
            connect(dialog, sig.toStdString().c_str() , this, SLOT(onSelectedDate()));
        }
    }
    QMetaObject::invokeMethod(dialog, "show", Q_ARG(QVariant, QVariant(QDate::currentDate())));
}

void MainWindow::onSelectedDate()
{
    ui->lineEdit->setText(dialog->property("selectedDate").toDate().toString());
    ui->lineEdit->adjustSize();
}

The complete code can be found at the following link.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241