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

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

И опять же во имя максимальной наглядности зададим в качестве частей 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();
}
}
}
Результат закономерен:

Единственный нюанс - наличествует белое поле вокруг contentItem, оно регулируется свойством padding. Добавляем:
Dialog {
id: testDialog
title: "Test dialog title"
standardButtons: Dialog.Ok | Dialog.Cancel
implicitWidth: parent.width
implicitHeight: parent.height
padding: 0
// ...............

Таким образом, получили результат, полностью повторяющий схему 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() |
Вернемся к нашему самому первому диалогу с дефолтным набором параметров:

И добавим два обработчика:
onAcceptedonRejected
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();
}
}
}

В результате нажатия на 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" никаких действий не предпринимаем. В примере задействовано по максимуму различных свойств, чтобы при желании можно было легко адаптировать под свои конкретные нужды. Результат выглядит так:

И код:
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();
}
}
}
На этом на сегодня и заканчиваем 🤝




Здравствуйте!
Это Дмитрий (Инстаграм: kupratsevich_dima), писал вам раньше про покупку сайта microtechnics.ru, но не получил ответа.
Возможно, что не устроила цена. Готов рассмотреть по рыночной оценке.
Мои контакты:
kupratsevich (Telegram)
kuprdimasites@gmail.com (Почта)
+79959176538 (Телефон/whatsapp)
Добрый день!
Благодарю за предложение, не интересует в целом.