Top.Mail.Ru

Qt. QML Dialog. Свойства, события и сигналы, кастомизация стиля.

Возвращаемся к курсу по QML и сегодня продолжим рассмотрение основных типов и компонентов. Подошла очередь QML Dialog, собственно, им и займемся. Все по привычной схеме - рассмотрим теоретически-обзорные моменты, по максимуму сопровождая их наглядными практическими примерами, так что переходим к делу. Использовать будем Dialog из QtQuick.Controls 2.15 (не QtQuick.Dialogs 1.3).

QML Dialog. Основные свойства и методы.

Итак, компонент Dialog по сути представляет из себя окно, предлагающее пользователю осуществить те или иные действия, допустим, сохранить или загрузить информацию в файл/из файла. Схематично имеем следующее:

QML Dialog структура

То есть диалоговое окно состоит из трех отдельных частей:

  • header
  • contentItem
  • footer

И, поскольку я предпочитаю любые теоретические аспекты демонстрировать на конкретном примере, то так и поступим. Создаем пустое Qt Quick приложение и добавляем к нему два элемента:

  • кнопку, по нажатию на которую будет происходить открытие диалогового окна
  • и непосредственно этот самый Dialog

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

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Window {
    width: 320
    height: 240
    visible: true
    title: qsTr("QML Dialog Review")

    Dialog {
        id: testDialog
        title: "Test dialog title"
        standardButtons: Dialog.Ok | Dialog.Cancel

        implicitWidth: parent.width
        implicitHeight: parent.height
    }

    Button {
        id: openDialogButton
        anchors.centerIn: parent
        text: qsTr("Open Dialog")

        onClicked: {
            testDialog.open();
        }
    }
}

Здесь мы помимо физических параметров, а именно ширины и высоты, задали еще title и standardButtons. По дефолту (когда header, contentItem и footer не заданы явно) данные части диалогового окна представляют из себя следующее:

  • в качестве header - заголовок, содержащий текст, введенный в title
  • contentItem остается пустым
  • footer же состоит из DialogButtonBox, содержащим кнопки, указанные в standardButtons

Запускаем приложение и нажимаем на кнопку:

Базовый вид QML Dialog

Соответственно, наблюдаем ровно то, что и планировали:

Содержание диалога

И опять же во имя максимальной наглядности зададим в качестве частей Dialog элементы Rectangle разных цветов, дабы оценить их взаимное расположение:

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Window {
    width: 320
    height: 240
    visible: true
    title: qsTr("QML Dialog Review")

    Dialog {
        id: testDialog
        title: "Test dialog title"
        standardButtons: Dialog.Ok | Dialog.Cancel

        implicitWidth: parent.width
        implicitHeight: parent.height

        header: Rectangle {
            color: "red"
            height: 50
        }

        contentItem: Rectangle {
            color: "green"

        }

        footer: Rectangle {
            color: "blue"
            height: 50
        }
    }

    Button {
        id: openDialogButton
        anchors.centerIn: parent
        text: qsTr("Open Dialog")

        onClicked: {
            testDialog.open();
        }
    }
}

Результат закономерен:

QML Dialog пример

Единственный нюанс - наличествует белое поле вокруг contentItem, оно регулируется свойством padding. Добавляем:

Dialog {
	id: testDialog
	title: "Test dialog title"
	standardButtons: Dialog.Ok | Dialog.Cancel

	implicitWidth: parent.width
	implicitHeight: parent.height
	
	padding: 0
// ...............
Padding

Таким образом, получили результат, полностью повторяющий схему Dialog из начала статьи 👍

Полный список свойств доступен в официальной документации Qt, мы же кратко пробежимся по паре наиболее часто используемых, а именно:

  • modal - определяет, является ли окно модальным, то есть блокирующим взаимодействие с остальным приложением до своего закрытия. Возможные значения: true/false.
  • result - хранит в себе результат работы окна, значения: Dialog.Accepted/Dialog.Rejected (1/0).

Этот самый результат зависит от того, каким образом было закрыто диалоговое окно. И тут копнем чуть глубже... В качестве кнопок Dialog (которые мы задавали в standardButtons) может быть использован довольно внушительный ряд различных вариантов. При этом у каждой кнопки, в свою очередь, есть определенная роль (DialogButtonBox.buttonRole), назначенная ей. А уже каждой роли соответствует определенный сигнал. Так мы плавно и логично перешли к следующему подразделу.

QML Dialog. События и сигналы.

Так вот, вышеописанное я систематизировал следующим образом:

Button Text Role Signal
Dialog.Ok "OK" AcceptRole accepted()
Dialog.Open "Open" AcceptRole accepted()
Dialog.Save "Save" AcceptRole accepted()
Dialog.Cancel "Cancel" RejectRole rejected()
Dialog.Close "Close" RejectRole rejected()
Dialog.Discard "Discard" DiscardRole discarded()
Dialog.Apply "Apply" ApplyRole applied()
Dialog.Reset "Reset" ResetRole reset()
Dialog.RestoreDefaults "Restore Defaults" ResetRole reset()
Dialog.Help "Help" HelpRole helpRequested()
Dialog.SaveAll "Save All" AcceptRole accepted()
Dialog.Yes "Yes" YesRole accepted()
Dialog.YesToAll "Yes to All" YesRole accepted()
Dialog.No "No" NoRole rejected()
Dialog.NoToAll "No to All" NoRole rejected()
Dialog.Abort "Abort" RejectRole rejected()
Dialog.Retry "Retry" AcceptRole accepted()
Dialog.Ignore "Ignore" AcceptRole accepted()

Вернемся к нашему самому первому диалогу с дефолтным набором параметров:

QML Dialog, стандартный вид

И добавим два обработчика:

  • onAccepted
  • onRejected
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Window {
    width: 320
    height: 240
    visible: true
    title: qsTr("QML Dialog Review")

    Dialog {
        id: testDialog
        title: "Test dialog title"
        standardButtons: Dialog.Ok | Dialog.Cancel

        implicitWidth: parent.width
        implicitHeight: parent.height

        onAccepted: {
            console.log("Ok button clicked " + testDialog.result);
        }

        onRejected: {
            console.log("Cancel button clicked " + testDialog.result);
        }
    }

    Button {
        id: openDialogButton
        anchors.centerIn: parent
        text: qsTr("Open Dialog")

        onClicked: {
            testDialog.open();
        }
    }
}

При нажатии на кнопки Ok и Cancel в консоли получаем:

  • Кнопка Ok: "Ok button clicked 1".
  • Кнопка Cancel: "Cancel button clicked 0".

Что соответствует значениям result, равным Dialog.Accepted в первом случае и Dialog.Rejected - во втором.

Аналогичный механизм для добавления других кнопок и обработчиков сигналов, например:

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Window {
    width: 320
    height: 240
    visible: true
    title: qsTr("QML Dialog Review")

    Dialog {
        id: testDialog
        title: "Test dialog title"
        standardButtons: Dialog.Ok | Dialog.Apply |  Dialog.Cancel

        implicitWidth: parent.width
        implicitHeight: parent.height

        onAccepted: {
            console.log("Ok button clicked " + testDialog.result);
        }

        onRejected: {
            console.log("Cancel button clicked " + testDialog.result);
        }

        onApplied: {
            console.log("Apply button clicked " + testDialog.result);
        }
    }

    Button {
        id: openDialogButton
        anchors.centerIn: parent
        text: qsTr("Open Dialog")

        onClicked: {
            testDialog.open();
        }
    }
}
Обработка сигналов QML

В результате нажатия на Apply ("Применить") получаем в консоли: "Apply button clicked 1". При этом обратите внимание, что нажатие на Apply не приводит к закрытию диалога.

Плюс ко всему Dialog имеет ряд методов, позволяющих "вручную" осуществить действия, аналогичные нажатию кнопок:

  • void accept() - закрывает диалоговое окно и генерирует сигнал accepted().
  • void done(int result) - также закрывает диалог и устанавливает свойство result диалога равным одноименному аргументу данной функции. При вызове с аргументом Dialog.Accepted (done(Dialog.Accepted)) будет сгенерирован сигнал accepted(), а если вызываем done(Dialog.Rejected), то будет уже сигнал rejected(), что согласитесь, логично.
  • void reject() - аналогично закрывает Dialog и генерирует сигнал rejected().

На этом в целом заканчиваем с рассмотрением нюансов работы с QML Dialog, перейдем к еще одному практическому примеру.

QML Dialog. Кастомизация, пример.

Итак, я сделал простенькое диалоговое окно, которое используется для закрытия приложения. При нажатии "Ok" как раз и произойдет закрытие, а при нажатии "Cancel" никаких действий не предпринимаем. В примере задействовано по максимуму различных свойств, чтобы при желании можно было легко адаптировать под свои конкретные нужды. Результат выглядит так:

QML Dialog кастомизация

И код:

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Window {
    width: 320
    height: 240
    visible: true
    title: qsTr("QML Dialog Review")

    Dialog {
        id: closeAppDialog
        title: "Close Application"

        implicitWidth: parent.width
        implicitHeight: parent.height

        padding: 0

        header:
            Label {
                text: closeAppDialog.title
                horizontalAlignment: Text.AlignHCenter
                color: "#ffffff"
                font.bold: true

                padding: 10

                background: Rectangle {
                    color: "#707070"
                    border.width: 1.0
                    border.color: "#000000"
                }
        }

        contentItem:
            Label {
                text: qsTr("Are you sure?")
                font.pointSize: 12
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
                color: "#ffffff"
                font.bold: true

                padding: 10

                background: Rectangle {
                    color: "#353535"
                }
        }

        footer: DialogButtonBox {
            background: Rectangle {
                color: "#707070"

                border.width: 1.0
                border.color: "#000000"
            }

            Button {
                DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole

                contentItem: Text {
                    text: qsTr("Ok")
                    color: "#ffffff"
                    horizontalAlignment: Text.AlignHCenter
                    verticalAlignment: Text.AlignVCenter
                    font.pointSize: 10
                }

                background: Rectangle {
                    color: "#8fbc8f"
                    radius: 10

                    border.width: 1.0
                    border.color: "#006400"
                }
            }

            Button {
                DialogButtonBox.buttonRole: DialogButtonBox.RejectRole

                contentItem: Text {
                    text: qsTr("Cancel")
                    color: "#ffffff"
                    horizontalAlignment: Text.AlignHCenter
                    verticalAlignment: Text.AlignVCenter
                    font.pointSize: 10
                }

                background: Rectangle {
                    color: "#cd5c5c"
                    radius: 10

                    border.width: 1.0
                    border.color: "#8b0000"
                }
            }
        }

        onAccepted: {
            Qt.quit();
        }

        onRejected: {
            // Nothing to be done
        }
    }

    Button {
        id: closeAppButton
        anchors.centerIn: parent
        text: qsTr("Close")

        onClicked: {
            closeAppDialog.open();
        }
    }
}

На этом на сегодня и заканчиваем 🤝

Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x