Top.Mail.Ru

Qt и QML. Button. События, кастомизация, стили, примеры.

Рад снова всех приветствовать! Как известно, спрос рождает предложение, поэтому я решил опубликовать цикл статей, посвященных различным аспектам QML 👍 Пройдемся более менее масштабно, начиная с основных интерактивных элементов для взаимодействия с пользователем, таких как Button, CheckBox, ComboBox и т. д.... И не оставим в стороне также более узконаправленные нюансы. При этом среди вопросов по этой тематике добрую половину представляют из себя вопросы по кастомизации стиля и внешнего вида элементов. Соответственно, этому уделим отдельное внимание, конечно же, все будет сопровождаться конкретными практическими примерами.

Не знал, с чего именно начать, но по факту последовательность тут особой роли не играет, так что без веской на то причины первым героем данного цикла будет тип Button. И в качестве отправной точки стабильно будем использовать пустой Qt Quick проект:

Qt Quick project.

В итоге имеем проект с двумя файлами с дефолтным содержимым, main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>



int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

И main.qml:

import QtQuick 2.15
import QtQuick.Window 2.15



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

Для использования Button сразу импортируем:

import QtQuick.Controls 2.15

QML Button. Создание.

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

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



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

    Button {
        id: testButton
        anchors.centerIn: parent
        text: qsTr("testButton")
    }
}
Default QML button.

Как и для практически любого компонента QML непосредственно добавление осуществляется элементарно, в чем мы и убедились. Вид на данный момент Button имеет дефолтный, ничем не примечательный, кастомизацией займемся чуть позже. Но прежде рассмотрим кратко функционал...

QML Button. События.

Итак, кнопка создана для того, чтобы ее нажимали. Поэтому разберемся, как обработать данное действие пользователя. И все также максимально просто, при помощи обработчика - onClicked:

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

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

        onClicked: {
            console.log("testButton clicked");
        }
    }
}

Здесь мы по нажатию выводим строку в консоль. Пример настолько прост, что просто вгоняет в краску, поэтому минимально, но усложним. Добавим под кнопку текст, в который при нажатии будем выводить количество кликов по кнопке:

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

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

        property var clickCounter: 0

        onClicked: {
            clickCounter++;
            testButtonClicks.text = qsTr("testButton clicked: ") + clickCounter;
        }
    }

    Text {
        id: testButtonClicks
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: testButton.bottom
        anchors.topMargin: 10

        text: qsTr("No clicks")
    }
}
Обработка событий.

Button наследует от AbstractButton, поэтому именно здесь определена и описана подавляющая часть свойств и методов. В частности, сигналы, для каждого из которых существует свой обработчик вида onИмяСигнала:

  • onCanceled
  • onClicked
  • onDoubleClicked
  • onPressAndHold
  • onPressed
  • onReleased
  • onToggled

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

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

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

        property var clickCounter: 0

        onClicked: {
            clickCounter++;
            testButtonClicks.text = qsTr("testButton clicked: ") + clickCounter;
            testButtonLastEvent.text = qsTr("testButton: clicked");
        }

        onDoubleClicked: {
            testButtonLastEvent.text = qsTr("testButton: doubleCilcked");
        }

        onPressAndHold: {
            testButtonLastEvent.text = qsTr("testButton: pressAndHold");
        }

        onPressed: {
            testButtonLastEvent.text = qsTr("testButton: pressed");
        }
    }

    Text {
        id: testButtonClicks
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: testButton.bottom
        anchors.topMargin: 10

        text: qsTr("No clicks")
    }

    Text {
        id: testButtonLastEvent
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: testButtonClicks.bottom
        anchors.topMargin: 10

        text: qsTr("No event")
    }
}
Qt QML Button.

Таким вот образом можно спокойно поэкспериментировать и на практике ощутить, какой смысл в себе несет тот или иной сигнал, сопутствующий пользовательским действиям.

Так, кроме всего прочего, интерфейс часто требует наличия кнопки, которая выступает в роли переключателя. То есть не просто отрабатывает события нажатия и т. д., но может находиться в двух состояниях - нажатом и не нажатом. Естественно, обойти это стороной нельзя. Реализация также очень проста:

  • изменяем свойство checkable кнопки, ставим true
  • добавим обработчик onToggled
  • текущее состояние кнопки доступно через свойство checked, в контексте нашего примера - testButton.checked

Убираем "лишние" обработчики и получаем следующий базовый пример использования:

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

    Button {
        id: testButton
        anchors.centerIn: parent
        text: qsTr("testButton")
        checkable: true

        onToggled: {
            testButtonLastEvent.text = qsTr("testButton: onToggled ") + testButton.checked;
        }
    }

    Text {
        id: testButtonClicks
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: testButton.bottom
        anchors.topMargin: 10

        text: qsTr("No clicks")
    }

    Text {
        id: testButtonLastEvent
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: testButtonClicks.bottom
        anchors.topMargin: 10

        text: qsTr("No event")
    }
}
Пример использования checkable.

При нажатии меняется состояние кнопки, а также ее цвет. Стиль мы вообще не трогали пока, тем не менее стиль по умолчанию предусматривает изменение цвета при разных действиях. В общем-то, самое время как раз и перейти к кастомизации внешнего вида.

QML Button. Стили. Кастомизация.

Давайте изначально систематизируем - у кнопки есть два объекта для настройки стиля - непосредственно сама прямоугольная область и текст, заключенный внутри нее. Поэтому QML предоставляет нам два соответствующих свойства:

  • background
  • contentItem

Лучше всего разобраться можно на конкретных примерах, к ним и переходим. Для начала сделаем минимально необходимые вещи, а затем будем постепенно добавлять:

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

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

        contentItem: Text {
            text: testButton.text
            color: "#ffffff"
        }

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

Полезные ссылки - Rectangle, Text - и результат:

Стиль Button.

Увеличим размер кнопки:

background: Rectangle {
	implicitWidth: 100
	implicitHeight: 50
	color: "#005291"
}
Изменение стиля.

Проблема налицо, разместим текст по центру и сразу же немного увеличим шрифт:

contentItem: Text {
	text: testButton.text
	color: "#ffffff"
	horizontalAlignment: Text.AlignHCenter
	verticalAlignment: Text.AlignVCenter
	font.pointSize: 10
	font.bold: true
}
Пример Button в QML.

Уважающая себя кнопка должна иметь отклик в виде изменения оформления при действиях пользователя - наведении курсора, нажатии кнопки и т. д. Поэтому добавим цвета:

  • normalColor - #005291 - текущий цвет
  • hoveredColor - #4587ba - цвет при наведении
  • pressedColor - #002948 - цвет при нажатии
Window {
    width: 320
    height: 240
    visible: true
    title: qsTr("QML Button Review")

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

        contentItem: Text {
            text: testButton.text
            color: "#ffffff"
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
            font.pointSize: 10
            font.bold: true
        }

        background: Rectangle {
            property var normalColor: "#005291"
            property var hoveredColor: "#4587ba"
            property var pressedColor: "#002948"

            implicitWidth: 100
            implicitHeight: 50
            color: testButton.pressed ? pressedColor :
                   testButton.hovered ? hoveredColor :
                                        normalColor
        }
    }
}
Кастомизация стиля кнопки.

С этим разобрались, теперь мы имеем весь необходимый функционал, предлагаю рассмотреть еще один пример, с градиентами. Про градиенты будет отдельная статья (может быть), так что здесь просто, отбросив сомнения, используем. Добавим еще скругление углов кнопки и рамку по периметру, чтобы охватить бОльшее количество доступных свойств:

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

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

        contentItem: Text {
            text: testButton.text
            color: "#ffffff"
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
            font.pointSize: 10
        }

        background: Rectangle {
            Gradient {
                id: normalGradient

                GradientStop { position: 0.0; color: "#252525" }
                GradientStop { position: 0.5; color: "#e30000" }
                GradientStop { position: 1.0; color: "#252525" }
            }

            Gradient {
                id: hoveredGradient

                GradientStop { position: 0.0; color: "#252525" }
                GradientStop { position: 0.5; color: "#ff5e5e" }
                GradientStop { position: 1.0; color: "#252525" }
            }

            Gradient {
                id: pressedGradient

                GradientStop { position: 0.0; color: "#252525" }
                GradientStop { position: 0.5; color: "#b00000" }
                GradientStop { position: 1.0; color: "#252525" }
            }

            implicitWidth: 100
            implicitHeight: 50
            gradient: testButton.pressed ? pressedGradient :
                      testButton.hovered ? hoveredGradient :
                                           normalGradient
            radius: 10
            border.width: 2.0
            border.color: "#000000"
        }
    }
}

Ну и, пожалуй, на этом сегодня и остановимся, до встречи🤝 Если возникли какие-либо вопросы или проблемы, буду рад помочь с решением, пишите в комментарии, либо на форум.

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