Spec-Zone.ru › Qt 5.14

Настройка Qt Quick Controls

Qt Quick Controls состоят из иерархии (дерева) элементов. Для предоставления пользовательского вида и ощущения можно заменить стандартную реализацию QML каждого элемента на пользовательскую.

Настройка элемента управления

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

Первый способ создания такой кнопки — просто определить её на месте, где она нужна. Например, предположим, что вас не устраивает стандартная стилизация кнопки с квадратными углами. Чтобы сделать углы скругленными, можно переопределить элемент background и задать свойство радиуса элемента Rectangle:

import QtQuick 2.14
import QtQuick.Controls 2.14

ApplicationWindow {
    width: 400
    height: 400
    visible: true

    Button {
        id: button
        text: "A Special Button"
        background: Rectangle {
            implicitWidth: 100
            implicitHeight: 40
            color: button.down ? "#d6d6d6" : "#f6f6f6"
            border.color: "#26282a"
            border.width: 1
            radius: 4
        }
    }
}

Второй способ создания кнопки полезен, если вы планируете использовать вашу скругленную кнопку в нескольких местах. Он включает перемещение кода в отдельный файл QML в вашем проекте.

Для этого подхода скопируем код фона из стандартной стилизации Button.qml. Этот файл можно найти в следующей директории вашей установки Qt:

$QTDIR/qml/QtQuick/Controls.2/Button.qml

После этого просто добавьте следующую строку:

radius: 4

Чтобы избежать путаницы с элементами управления в самом модуле, назовем файл MyButton.qml. Чтобы использовать элемент управления в вашем приложении, ссылайтесь на него по имени файла:

import QtQuick.Controls 2.14

ApplicationWindow {
    MyButton {
        text: qsTr("A Special Button")
    }
}

Третий способ создания кнопки немного более структурирован, как в плане расположения файла в файловой системе, так и в плане его использования в QML. Сначала скопируйте существующий файл, как и в предыдущем случае, но на этот раз поместите его в подпапку в вашем проекте, например, controls. Чтобы использовать элемент управления, сначала импортируйте папку в пространство имён:

import QtQuick.Controls 2.14
import "controls" as MyControls

ApplicationWindow {
    MyControls.Button {
        text: qsTr("A Special Button")
    }
}

Теперь у вас есть пространство имён MyControls, и вы можете именовать элементы управления по их реальным аналогам в модуле Qt Quick Controls. Вы можете повторить этот процесс для любого элемента управления, который хотите добавить.

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

Создание пользовательской стилизации

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

Определение стилизации

В Qt Quick Controls стилизация представляет собой набор взаимозаменяемых файлов QML в отдельной директории. Для того чтобы стилизация была используемой, должны быть выполнены три требования:

  • Должен существовать хотя бы один файл QML, имя которого соответствует элементу управления (например, Button.qml).
  • Каждый файл QML должен содержать соответствующий тип из импорта QtQuick.Templates в качестве корневого элемента. Например, Button.qml должен содержать шаблон Button в качестве корневого элемента.

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

  • Файлы должны находиться в директории в файловой системе или в системе ресурсов.

    Например, это допустимые пути к стилизации:

    • ./myapp -style /home/absolute/path/to/my/style
    • ./myapp -style :/mystyle
    • ./myapp -style relative/path/to/my/style
    • ./myapp -style MyStyle

    Третий и четвёртый пути будут проверены в списке путей импорта движка QML. Это аналогично тому, что происходит, когда вы передаёте Material в качестве стилизации, например.

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

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

Предварительный просмотр пользовательских стилизации в Qt Quick Designer

Используя описанный выше подход, можно предварительно просмотреть пользовательскую стилизацию в Qt Quick Designer. Для этого убедитесь, что проект содержит файл qtquickcontrols2.conf и что в нём существует следующая запись:

[Controls]
Style=MyStyle

Дополнительную информацию можно найти в примере Flat Style.

Модульные расширения C++ для стилизации

Иногда для расширения пользовательской стилизации может потребоваться использовать C++. Есть два способа экспонировать такие типы в QML:

  • Если стилизация, использующая тип, является единственной стилизации, используемой приложением, достаточно зарегистрировать её в движке QML с помощью qmlRegisterType():
    qmlRegisterType<ACoolCppItem>("MyApp", 1, 0, "ACoolItem");

    Дополнительную информацию об этом можно найти в разделе Использование данных C++ из QML.

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

    Использование плагина в качестве части вашей стилизации не сильно отличается от использования набора файлов QML. Единственное отличие состоит в том, что плагин и его qmldir файл должны находиться в той же директории, что и файлы QML.

Присоединённые свойства

Часто стилизация имеет определённые свойства или атрибуты, которые применяются ко всем элементам управления. Присоединённые свойства — отличный способ расширения элемента в QML без необходимости изменения существующего C++ этого элемента. Например, в стилизациях Material и Universal есть присоединённое свойство темы, которое управляет тем, будут ли элемент и его дочерние элементы отображаться в светлой или тёмной теме.

В качестве примера добавим присоединённое свойство, которое контролирует высоту подъёма. Наша стилизация проиллюстрирует высоту подъёма с помощью теней; чем выше подъём, тем больше тень.

Первым шагом является создание нового приложения Qt Quick Controls 2 в Qt Creator. После этого мы добавляем тип C++, который хранит высоту подъёма. Поскольку тип будет использоваться для каждого элемента управления, поддерживаемого нашей стилизацией, и поскольку мы, возможно, захотим добавить другие присоединённые свойства позже, мы назовём его MyStyle. Вот MyStyle.h:

#ifndef MYSTYLE_H
#define MYSTYLE_H

#include <QObject>
#include <QtQml>

class MyStyle : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int elevation READ elevation WRITE setElevation NOTIFY elevationChanged)

public:
    explicit MyStyle(QObject *parent = nullptr);

    static MyStyle *qmlAttachedProperties(QObject *object);

    int elevation() const;
    void setElevation(int elevation);

signals:
    void elevationChanged();

private:
    int m_elevation;
};

QML_DECLARE_TYPEINFO(MyStyle, QML_HAS_ATTACHED_PROPERTIES)

#endif // MYSTYLE_H

MyStyle.cpp:

#include "mystyle.h"

MyStyle::MyStyle(QObject *parent) :
    QObject(parent),
    m_elevation(0)
{
}

MyStyle *MyStyle::qmlAttachedProperties(QObject *object)
{
    return new MyStyle(object);
}

int MyStyle::elevation() const
{
    return m_elevation;
}

void MyStyle::setElevation(int elevation)
{
    if (elevation == m_elevation)
        return;

    m_elevation = elevation;
    emit elevationChanged();
}

Тип MyStyle является специальным в том смысле, что он не должен создаваться, а используется для своих присоединённых свойств. По этой причине мы регистрируем его таким образом в main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include "mystyle.h"

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

    qmlRegisterUncreatableType<MyStyle>("MyStyle", 1, 0, "MyStyle", "MyStyle is an attached property");

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

    return app.exec();
}

Затем мы копируем Button.qml из стандартной стилизации в $QTDIR/qml/QtQuick/Controls.2/ в новую папку myproject в нашем каталоге проекта. Добавьте скопированный Button.qml в qml.qrc, который является файлом ресурсов, содержащим наши QML файлы.

Далее мы добавляем тень в делегат background кнопки:

// ...
import QtGraphicalEffects 1.14
import MyStyle 1.0
// ...

background: Rectangle {
    // ...

    layer.enabled: control.enabled && control.MyStyle.elevation > 0
    layer.effect: DropShadow {
        verticalOffset: 1
        color: control.visualFocus ? "#330066ff" : "#aaaaaa"
        samples: control.MyStyle.elevation
        spread: 0.5
    }
}

Обратите внимание, что мы:

  • Не используем тень, когда подъём равен 0
  • Изменяем цвет тени в зависимости от того, имеет ли кнопка фокус
  • Делаем размер тени зависящим от подъёма

Чтобы попробовать присоединённое свойство, создадим Row с двумя кнопками в main.qml:

import QtQuick 2.14
import QtQuick.Controls 2.14

import MyStyle 1.0

ApplicationWindow {
    id: window
    width: 400
    height: 400
    visible: true

    Row {
        spacing: 20
        anchors.centerIn: parent

        Button {
            text: "Button 1"
        }
        Button {
            text: "Button 2"
            MyStyle.elevation: 10
        }
    }
}

Одна кнопка не имеет подъёма, а другая имеет подъём 10.

После этого мы можем запустить наш пример. Чтобы указать приложению использовать нашу новую стилизацию, мы передаём -style :/mystyle как аргумент приложения, но есть много способов указания используемой стилизации.

Конечный результат:

Обратите внимание, что оператор import MyStyle 1.0 необходим только потому, что мы используем присоединённое свойство, принадлежащее MyStyle. Обе кнопки будут использовать нашу пользовательскую стилизацию, даже если мы удалим импорт.

Справочник по настройке

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

Настройка ApplicationWindow

ApplicationWindow состоит из одного визуального элемента: background. Также можно настроить элементы modal и modeless.

import QtQuick 2.14
import QtQuick.Controls 2.14

ApplicationWindow {
    visible: true

    background: Rectangle {
        gradient: Gradient {
            GradientStop { position: 0; color: "#ffffff" }
            GradientStop { position: 1; color: "#c1bbf9" }
        }
    }

    overlay.modal: Rectangle {
        color: "#8f28282a"
    }

    overlay.modeless: Rectangle {
        color: "#2f28282a"
    }
}

Настройка BusyIndicator

BusyIndicator состоит из двух визуальных элементов: background и contentItem.

import QtQuick 2.12
import QtQuick.Controls 2.12

BusyIndicator {
    id: control

    contentItem: Item {
        implicitWidth: 64
        implicitHeight: 64

        Item {
            id: item
            x: parent.width / 2 - 32
            y: parent.height / 2 - 32
            width: 64
            height: 64
            opacity: control.running ? 1 : 0

            Behavior on opacity {
                OpacityAnimator {
                    duration: 250
                }
            }

            RotationAnimator {
                target: item
                running: control.visible && control.running
                from: 0
                to: 360
                loops: Animation.Infinite
                duration: 1250
            }

            Repeater {
                id: repeater
                model: 6

                Rectangle {
                    x: item.width / 2 - width / 2
                    y: item.height / 2 - height / 2
                    implicitWidth: 10
                    implicitHeight: 10
                    radius: 5
                    color: "#21be2b"
                    transform: [
                        Translate {
                            y: -Math.min(item.width, item.height) * 0.5 + 5
                        },
                        Rotation {
                            angle: index / repeater.count * 360
                            origin.x: 5
                            origin.y: 5
                        }
                    ]
                }
            }
        }
    }
}

Настройка Button

Button состоит из двух визуальных элементов: background и элемент содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

Button {
    id: control
    text: qsTr("Button")

    contentItem: Text {
        text: control.text
        font: control.font
        opacity: enabled ? 1.0 : 0.3
        color: control.down ? "#17a81a" : "#21be2b"
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
        elide: Text.ElideRight
    }

    background: Rectangle {
        implicitWidth: 100
        implicitHeight: 40
        opacity: enabled ? 1 : 0.3
        border.color: control.down ? "#17a81a" : "#21be2b"
        border.width: 1
        radius: 2
    }
}

Настройка CheckBox

CheckBox состоит из трёх визуальных элементов: background, contentItem и indicator.

import QtQuick 2.12
import QtQuick.Controls 2.12

CheckBox {
    id: control
    text: qsTr("CheckBox")
    checked: true

    indicator: Rectangle {
        implicitWidth: 26
        implicitHeight: 26
        x: control.leftPadding
        y: parent.height / 2 - height / 2
        radius: 3
        border.color: control.down ? "#17a81a" : "#21be2b"

        Rectangle {
            width: 14
            height: 14
            x: 6
            y: 6
            radius: 2
            color: control.down ? "#17a81a" : "#21be2b"
            visible: control.checked
        }
    }

    contentItem: Text {
        text: control.text
        font: control.font
        opacity: enabled ? 1.0 : 0.3
        color: control.down ? "#17a81a" : "#21be2b"
        verticalAlignment: Text.AlignVCenter
        leftPadding: control.indicator.width + control.spacing
    }
}

Настройка CheckDelegate

CheckDelegate состоит из трёх визуальных элементов: background, contentItem и indicator.

import QtQuick 2.12
import QtQuick.Controls 2.12

CheckDelegate {
    id: control
    text: qsTr("CheckDelegate")
    checked: true

    contentItem: Text {
        rightPadding: control.indicator.width + control.spacing
        text: control.text
        font: control.font
        opacity: enabled ? 1.0 : 0.3
        color: control.down ? "#17a81a" : "#21be2b"
        elide: Text.ElideRight
        verticalAlignment: Text.AlignVCenter
    }

    indicator: Rectangle {
        implicitWidth: 26
        implicitHeight: 26
        x: control.width - width - control.rightPadding
        y: control.topPadding + control.availableHeight / 2 - height / 2
        radius: 3
        color: "transparent"
        border.color: control.down ? "#17a81a" : "#21be2b"

        Rectangle {
            width: 14
            height: 14
            x: 6
            y: 6
            radius: 2
            color: control.down ? "#17a81a" : "#21be2b"
            visible: control.checked
        }
    }

    background: Rectangle {
        implicitWidth: 100
        implicitHeight: 40
        visible: control.down || control.highlighted
        color: control.down ? "#bdbebf" : "#eeeeee"
    }
}

Настройка ComboBox

Комбобокс состоит из фонового элемента, элемента содержимого, выпадающего списка, индикатора и элемента делегата.

import QtQuick 2.12
import QtQuick.Controls 2.12

ComboBox {
    id: control
    model: ["First", "Second", "Third"]

    delegate: ItemDelegate {
        width: control.width
        contentItem: Text {
            text: modelData
            color: "#21be2b"
            font: control.font
            elide: Text.ElideRight
            verticalAlignment: Text.AlignVCenter
        }
        highlighted: control.highlightedIndex === index
    }

    indicator: Canvas {
        id: canvas
        x: control.width - width - control.rightPadding
        y: control.topPadding + (control.availableHeight - height) / 2
        width: 12
        height: 8
        contextType: "2d"

        Connections {
            target: control
            onPressedChanged: canvas.requestPaint()
        }

        onPaint: {
            context.reset();
            context.moveTo(0, 0);
            context.lineTo(width, 0);
            context.lineTo(width / 2, height);
            context.closePath();
            context.fillStyle = control.pressed ? "#17a81a" : "#21be2b";
            context.fill();
        }
    }

    contentItem: Text {
        leftPadding: 0
        rightPadding: control.indicator.width + control.spacing

        text: control.displayText
        font: control.font
        color: control.pressed ? "#17a81a" : "#21be2b"
        verticalAlignment: Text.AlignVCenter
        elide: Text.ElideRight
    }

    background: Rectangle {
        implicitWidth: 120
        implicitHeight: 40
        border.color: control.pressed ? "#17a81a" : "#21be2b"
        border.width: control.visualFocus ? 2 : 1
        radius: 2
    }

    popup: Popup {
        y: control.height - 1
        width: control.width
        implicitHeight: contentItem.implicitHeight
        padding: 1

        contentItem: ListView {
            clip: true
            implicitHeight: contentHeight
            model: control.popup.visible ? control.delegateModel : null
            currentIndex: control.highlightedIndex

            ScrollIndicator.vertical: ScrollIndicator { }
        }

        background: Rectangle {
            border.color: "#21be2b"
            radius: 2
        }
    }
}

Настройка DelayButton

Кнопки с задержкой состоит из двух визуальных элементов: фонового элемента и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

DelayButton {
    id: control
    checked: true
    text: qsTr("Delay\nButton")

    contentItem: Text {
        text: control.text
        font: control.font
        opacity: enabled ? 1.0 : 0.3
        color: "white"
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
        elide: Text.ElideRight
    }

    background: Rectangle {
        implicitWidth: 100
        implicitHeight: 100
        opacity: enabled ? 1 : 0.3
        color: control.down ? "#17a81a" : "#21be2b"
        radius: size / 2

        readonly property real size: Math.min(control.width, control.height)
        width: size
        height: size
        anchors.centerIn: parent

        Canvas {
            id: canvas
            anchors.fill: parent

            Connections {
                target: control
                onProgressChanged: canvas.requestPaint()
            }

            onPaint: {
                var ctx = getContext("2d")
                ctx.clearRect(0, 0, width, height)
                ctx.strokeStyle = "white"
                ctx.lineWidth = parent.size / 20
                ctx.beginPath()
                var startAngle = Math.PI / 5 * 3
                var endAngle = startAngle + control.progress * Math.PI / 5 * 9
                ctx.arc(width / 2, height / 2, width / 2 - ctx.lineWidth / 2 - 2, startAngle, endAngle)
                ctx.stroke()
            }
        }
    }
}

Настройка Циферблата

Циферблат состоит из двух визуальных элементов: фонового элемента и ручки.

import QtQuick 2.12
import QtQuick.Controls 2.12

Dial {
    id: control
    background: Rectangle {
        x: control.width / 2 - width / 2
        y: control.height / 2 - height / 2
        width: Math.max(64, Math.min(control.width, control.height))
        height: width
        color: "transparent"
        radius: width / 2
        border.color: control.pressed ? "#17a81a" : "#21be2b"
        opacity: control.enabled ? 1 : 0.3
    }

    handle: Rectangle {
        id: handleItem
        x: control.background.x + control.background.width / 2 - width / 2
        y: control.background.y + control.background.height / 2 - height / 2
        width: 16
        height: 16
        color: control.pressed ? "#17a81a" : "#21be2b"
        radius: 8
        antialiasing: true
        opacity: control.enabled ? 1 : 0.3
        transform: [
            Translate {
                y: -Math.min(control.background.width, control.background.height) * 0.4 + handleItem.height / 2
            },
            Rotation {
                angle: control.angle
                origin.x: handleItem.width / 2
                origin.y: handleItem.height / 2
            }
        ]
    }
}

Настройка Drawer

Панель Drawer может иметь визуальный фоновый элемент.

background: Rectangle {
    Rectangle {
        x: parent.width - 1
        width: 1
        height: parent.height
        color: "#21be2b"
    }
}

Настройка Frame

Рамка состоит из одного визуального элемента: фонового элемента.

import QtQuick 2.12
import QtQuick.Controls 2.12

Frame {
    background: Rectangle {
        color: "transparent"
        border.color: "#21be2b"
        radius: 2
    }

    Label {
        text: qsTr("Content goes here!")
    }
}

Настройка GroupBox

GroupBox состоит из двух визуальных элементов: фонового элемента и метки.

import QtQuick 2.12
import QtQuick.Controls 2.12

GroupBox {
    id: control
    title: qsTr("GroupBox")

    background: Rectangle {
        y: control.topPadding - control.bottomPadding
        width: parent.width
        height: parent.height - control.topPadding + control.bottomPadding
        color: "transparent"
        border.color: "#21be2b"
        radius: 2
    }

    label: Label {
        x: control.leftPadding
        width: control.availableWidth
        text: control.title
        color: "#21be2b"
        elide: Text.ElideRight
    }

    Label {
        text: qsTr("Content goes here!")
    }
}

Настройка ItemDelegate

Делегат элемента состоит из двух визуальных элементов: фонового элемента и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

ItemDelegate {
    id: control
    text: qsTr("ItemDelegate")

    contentItem: Text {
        rightPadding: control.spacing
        text: control.text
        font: control.font
        color: control.enabled ? (control.down ? "#17a81a" : "#21be2b") : "#bdbebf"
        elide: Text.ElideRight
        verticalAlignment: Text.AlignVCenter
    }

    background: Rectangle {
        implicitWidth: 100
        implicitHeight: 40
        opacity: enabled ? 1 : 0.3
        color: control.down ? "#dddedf" : "#eeeeee"

        Rectangle {
            width: parent.width
            height: 1
            color: control.down ? "#17a81a" : "#21be2b"
            anchors.bottom: parent.bottom
        }
    }
}

Настройка Label

Метка может иметь визуальный фоновый элемент.

import QtQuick 2.12
import QtQuick.Controls 2.12

Label {
    text: qsTr("Label")
    color: "#21be2b"
}

Настройка Меню

  • Меню состоит из визуального фонового элемента.
  • Элемент меню состоит из четырёх визуальных элементов: фонового, элемента содержимого, индикатора и стрелки.
  • Разделитель меню состоит из визуального фонового и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

Menu {
    id: menu

    Action { text: qsTr("Tool Bar"); checkable: true }
    Action { text: qsTr("Side Bar"); checkable: true; checked: true }
    Action { text: qsTr("Status Bar"); checkable: true; checked: true }

    MenuSeparator {
        contentItem: Rectangle {
            implicitWidth: 200
            implicitHeight: 1
            color: "#21be2b"
        }
    }

    Menu {
        title: qsTr("Advanced")
        // ...
    }

    topPadding: 2
    bottomPadding: 2

    delegate: MenuItem {
        id: menuItem
        implicitWidth: 200
        implicitHeight: 40

        arrow: Canvas {
            x: parent.width - width
            implicitWidth: 40
            implicitHeight: 40
            visible: menuItem.subMenu
            onPaint: {
                var ctx = getContext("2d")
                ctx.fillStyle = menuItem.highlighted ? "#ffffff" : "#21be2b"
                ctx.moveTo(15, 15)
                ctx.lineTo(width - 15, height / 2)
                ctx.lineTo(15, height - 15)
                ctx.closePath()
                ctx.fill()
            }
        }

        indicator: Item {
            implicitWidth: 40
            implicitHeight: 40
            Rectangle {
                width: 26
                height: 26
                anchors.centerIn: parent
                visible: menuItem.checkable
                border.color: "#21be2b"
                radius: 3
                Rectangle {
                    width: 14
                    height: 14
                    anchors.centerIn: parent
                    visible: menuItem.checked
                    color: "#21be2b"
                    radius: 2
                }
            }
        }

        contentItem: Text {
            leftPadding: menuItem.indicator.width
            rightPadding: menuItem.arrow.width
            text: menuItem.text
            font: menuItem.font
            opacity: enabled ? 1.0 : 0.3
            color: menuItem.highlighted ? "#ffffff" : "#21be2b"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            elide: Text.ElideRight
        }

        background: Rectangle {
            implicitWidth: 200
            implicitHeight: 40
            opacity: enabled ? 1 : 0.3
            color: menuItem.highlighted ? "#21be2b" : "transparent"
        }
    }

    background: Rectangle {
        implicitWidth: 200
        implicitHeight: 40
        color: "#ffffff"
        border.color: "#21be2b"
        radius: 2
    }
}

Настройка Панели меню

Панель меню может иметь визуальный фоновый элемент, а Элемент панели меню состоит из двух визуальных элементов: фонового и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

MenuBar {
    id: menuBar

    Menu { title: qsTr("File") }
    Menu { title: qsTr("Edit") }
    Menu { title: qsTr("View") }
    Menu { title: qsTr("Help") }

    delegate: MenuBarItem {
        id: menuBarItem

        contentItem: Text {
            text: menuBarItem.text
            font: menuBarItem.font
            opacity: enabled ? 1.0 : 0.3
            color: menuBarItem.highlighted ? "#ffffff" : "#21be2b"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            elide: Text.ElideRight
        }

        background: Rectangle {
            implicitWidth: 40
            implicitHeight: 40
            opacity: enabled ? 1 : 0.3
            color: menuBarItem.highlighted ? "#21be2b" : "transparent"
        }
    }

    background: Rectangle {
        implicitWidth: 40
        implicitHeight: 40
        color: "#ffffff"

        Rectangle {
            color: "#21be2b"
            width: parent.width
            height: 1
            anchors.bottom: parent.bottom
        }
    }
}

Настройка PageIndicator

Индикатор страниц состоит из фонового, элемента содержимого и элемента делегата.

import QtQuick 2.12
import QtQuick.Controls 2.12

PageIndicator {
    id: control
    count: 5
    currentIndex: 2

    delegate: Rectangle {
        implicitWidth: 8
        implicitHeight: 8

        radius: width / 2
        color: "#21be2b"

        opacity: index === control.currentIndex ? 0.95 : pressed ? 0.7 : 0.45

        Behavior on opacity {
            OpacityAnimator {
                duration: 100
            }
        }
    }
}

Настройка Pane

Панель Pane состоит из фонового элемента.

import QtQuick 2.12
import QtQuick.Controls 2.12

Pane {
    background: Rectangle {
        color: "#eeeeee"
    }

    Label {
        text: qsTr("Content goes here!")
    }
}

Настройка Popup

Выпадающее меню Popup состоит из фонового и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

Popup {
    id: popup
    background: Rectangle {
        implicitWidth: 200
        implicitHeight: 200
        border.color: "#444"
    }
    contentItem: Column {}
}

Настройка ProgressBar

Полоса прогресса состоит из двух визуальных элементов: фонового и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

ProgressBar {
    id: control
    value: 0.5
    padding: 2

    background: Rectangle {
        implicitWidth: 200
        implicitHeight: 6
        color: "#e6e6e6"
        radius: 3
    }

    contentItem: Item {
        implicitWidth: 200
        implicitHeight: 4

        Rectangle {
            width: control.visualPosition * parent.width
            height: parent.height
            radius: 2
            color: "#17a81a"
        }
    }
}

Настройка RadioButton

Радиокнопка состоит из трёх визуальных элементов: фонового, элемента содержимого и индикатора.

import QtQuick 2.12
import QtQuick.Controls 2.12

RadioButton {
    id: control
    text: qsTr("RadioButton")
    checked: true

    indicator: Rectangle {
        implicitWidth: 26
        implicitHeight: 26
        x: control.leftPadding
        y: parent.height / 2 - height / 2
        radius: 13
        border.color: control.down ? "#17a81a" : "#21be2b"

        Rectangle {
            width: 14
            height: 14
            x: 6
            y: 6
            radius: 7
            color: control.down ? "#17a81a" : "#21be2b"
            visible: control.checked
        }
    }

    contentItem: Text {
        text: control.text
        font: control.font
        opacity: enabled ? 1.0 : 0.3
        color: control.down ? "#17a81a" : "#21be2b"
        verticalAlignment: Text.AlignVCenter
        leftPadding: control.indicator.width + control.spacing
    }
}

Настройка RadioDelegate

Делегат радиокнопки состоит из трёх визуальных элементов: фонового, элемента содержимого и индикатора.

import QtQuick 2.12
import QtQuick.Controls 2.12

RadioDelegate {
    id: control
    text: qsTr("RadioDelegate")
    checked: true

    contentItem: Text {
        rightPadding: control.indicator.width + control.spacing
        text: control.text
        font: control.font
        opacity: enabled ? 1.0 : 0.3
        color: control.down ? "#17a81a" : "#21be2b"
        elide: Text.ElideRight
        verticalAlignment: Text.AlignVCenter
    }

    indicator: Rectangle {
        implicitWidth: 26
        implicitHeight: 26
        x: control.width - width - control.rightPadding
        y: parent.height / 2 - height / 2
        radius: 13
        color: "transparent"
        border.color: control.down ? "#17a81a" : "#21be2b"

        Rectangle {
            width: 14
            height: 14
            x: 6
            y: 6
            radius: 7
            color: control.down ? "#17a81a" : "#21be2b"
            visible: control.checked
        }
    }

    background: Rectangle {
        implicitWidth: 100
        implicitHeight: 40
        visible: control.down || control.highlighted
        color: control.down ? "#bdbebf" : "#eeeeee"
    }
}

Настройка RangeSlider

Ползунок с диапазоном состоит из трёх визуальных элементов: фонового, первой ручки и второй ручки.

import QtQuick 2.12
import QtQuick.Controls 2.12

RangeSlider {
    id: control
    first.value: 0.25
    second.value: 0.75

    background: Rectangle {
        x: control.leftPadding
        y: control.topPadding + control.availableHeight / 2 - height / 2
        implicitWidth: 200
        implicitHeight: 4
        width: control.availableWidth
        height: implicitHeight
        radius: 2
        color: "#bdbebf"

        Rectangle {
            x: control.first.visualPosition * parent.width
            width: control.second.visualPosition * parent.width - x
            height: parent.height
            color: "#21be2b"
            radius: 2
        }
    }

    first.handle: Rectangle {
        x: control.leftPadding + control.first.visualPosition * (control.availableWidth - width)
        y: control.topPadding + control.availableHeight / 2 - height / 2
        implicitWidth: 26
        implicitHeight: 26
        radius: 13
        color: control.first.pressed ? "#f0f0f0" : "#f6f6f6"
        border.color: "#bdbebf"
    }

    second.handle: Rectangle {
        x: control.leftPadding + control.second.visualPosition * (control.availableWidth - width)
        y: control.topPadding + control.availableHeight / 2 - height / 2
        implicitWidth: 26
        implicitHeight: 26
        radius: 13
        color: control.second.pressed ? "#f0f0f0" : "#f6f6f6"
        border.color: "#bdbebf"
    }
}

Настройка RoundButton

Круглая кнопка может настраиваться аналогично кнопке.

Настройка ScrollBar

Полоса прокрутки состоит из двух визуальных элементов: фонового и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

ScrollBar {
    id: control
    size: 0.3
    position: 0.2
    active: true
    orientation: Qt.Vertical

    contentItem: Rectangle {
        implicitWidth: 6
        implicitHeight: 100
        radius: width / 2
        color: control.pressed ? "#81e889" : "#c2f4c6"
    }
}

Настройка ScrollIndicator

Индикатор прокрутки состоит из двух визуальных элементов: фонового и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

ScrollIndicator {
    id: control
    size: 0.3
    position: 0.2
    active: true
    orientation: Qt.Vertical

    contentItem: Rectangle {
        implicitWidth: 2
        implicitHeight: 100
        color: "#c2f4c6"
    }
}

Настройка ScrollView

Область прокрутки состоит из фонового элемента и горизонтальной и вертикальной полос прокрутки.

ScrollView {
    id: control

    width: 200
    height: 200
    focus: true

    Label {
        text: "ABC"
        font.pixelSize: 224
    }

    ScrollBar.vertical: ScrollBar {
        parent: control
        x: control.mirrored ? 0 : control.width - width
        y: control.topPadding
        height: control.availableHeight
        active: control.ScrollBar.horizontal.active
    }

    ScrollBar.horizontal: ScrollBar {
        parent: control
        x: control.leftPadding
        y: control.height - height
        width: control.availableWidth
        active: control.ScrollBar.vertical.active
    }

    background: Rectangle {
        border.color: control.activeFocus ? "#21be2b" : "#bdbebf"
    }
}

Настройка Slider

Ползунок состоит из двух визуальных элементов: фонового и ручки.

import QtQuick 2.12
import QtQuick.Controls 2.12

Slider {
    id: control
    value: 0.5

    background: Rectangle {
        x: control.leftPadding
        y: control.topPadding + control.availableHeight / 2 - height / 2
        implicitWidth: 200
        implicitHeight: 4
        width: control.availableWidth
        height: implicitHeight
        radius: 2
        color: "#bdbebf"

        Rectangle {
            width: control.visualPosition * parent.width
            height: parent.height
            color: "#21be2b"
            radius: 2
        }
    }

    handle: Rectangle {
        x: control.leftPadding + control.visualPosition * (control.availableWidth - width)
        y: control.topPadding + control.availableHeight / 2 - height / 2
        implicitWidth: 26
        implicitHeight: 26
        radius: 13
        color: control.pressed ? "#f0f0f0" : "#f6f6f6"
        border.color: "#bdbebf"
    }
}

Настройка SpinBox

Поле ввода состоит из четырёх визуальных элементов: фонового, элемента содержимого, индикатора вверх и индикатора вниз.

import QtQuick 2.12
import QtQuick.Controls 2.12

SpinBox {
    id: control
    value: 50
    editable: true

    contentItem: TextInput {
        z: 2
        text: control.textFromValue(control.value, control.locale)

        font: control.font
        color: "#21be2b"
        selectionColor: "#21be2b"
        selectedTextColor: "#ffffff"
        horizontalAlignment: Qt.AlignHCenter
        verticalAlignment: Qt.AlignVCenter

        readOnly: !control.editable
        validator: control.validator
        inputMethodHints: Qt.ImhFormattedNumbersOnly
    }

    up.indicator: Rectangle {
        x: control.mirrored ? 0 : parent.width - width
        height: parent.height
        implicitWidth: 40
        implicitHeight: 40
        color: control.up.pressed ? "#e4e4e4" : "#f6f6f6"
        border.color: enabled ? "#21be2b" : "#bdbebf"

        Text {
            text: "+"
            font.pixelSize: control.font.pixelSize * 2
            color: "#21be2b"
            anchors.fill: parent
            fontSizeMode: Text.Fit
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
        }
    }

    down.indicator: Rectangle {
        x: control.mirrored ? parent.width - width : 0
        height: parent.height
        implicitWidth: 40
        implicitHeight: 40
        color: control.down.pressed ? "#e4e4e4" : "#f6f6f6"
        border.color: enabled ? "#21be2b" : "#bdbebf"

        Text {
            text: "-"
            font.pixelSize: control.font.pixelSize * 2
            color: "#21be2b"
            anchors.fill: parent
            fontSizeMode: Text.Fit
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
        }
    }

    background: Rectangle {
        implicitWidth: 140
        border.color: "#bdbebf"
    }
}

Настройка SplitView

Разделитель состоит из визуального элемента-ручки делегата.

SplitView {
    id: splitView
    anchors.fill: parent

    handle: Rectangle {
        implicitWidth: 4
        implicitHeight: 4
        color: SplitHandle.pressed ? "#81e889"
            : (SplitHandle.hovered ? Qt.lighter("#c2f4c6", 1.1) : "#c2f4c6")
    }

    Rectangle {
        implicitWidth: 150
        color: "#444"
    }
    Rectangle {
        implicitWidth: 50
        color: "#666"
    }
}

Настройка StackView

Стэковый просмотр может иметь визуальный фоновый элемент, и позволяет настраивать переходы, используемые для операций push, pop и replace.

import QtQuick 2.12
import QtQuick.Controls 2.12

StackView {
    id: control

    popEnter: Transition {
        XAnimator {
            from: (control.mirrored ? -1 : 1) * -control.width
            to: 0
            duration: 400
            easing.type: Easing.OutCubic
        }
    }

    popExit: Transition {
        XAnimator {
            from: 0
            to: (control.mirrored ? -1 : 1) * control.width
            duration: 400
            easing.type: Easing.OutCubic
        }
    }
}

Настройка SwipeDelegate

Делегат свайпа состоит из шести визуальных элементов: фонового, элемента содержимого, индикатора, swipe.left, swipe.right, и swipe.behind.

import QtQuick 2.12
import QtQuick.Controls 2.12

SwipeDelegate {
    id: control
    text: qsTr("SwipeDelegate")

    Component {
        id: component

        Rectangle {
            color: SwipeDelegate.pressed ? "#333" : "#444"
            width: parent.width
            height: parent.height
            clip: true

            Label {
                text: qsTr("Press me!")
                color: "#21be2b"
                anchors.centerIn: parent
            }
        }
    }

    swipe.left: component
    swipe.right: component

    contentItem: Text {
        text: control.text
        font: control.font
        color: control.enabled ? (control.down ? "#17a81a" : "#21be2b") : "#bdbebf"
        elide: Text.ElideRight
        verticalAlignment: Text.AlignVCenter

        Behavior on x {
            enabled: !control.down
            NumberAnimation {
                easing.type: Easing.InOutCubic
                duration: 400
            }
        }
    }
}

Настройка SwipeView

Просмотр свайпа может иметь визуальный фоновый элемент. Навигация реализуется элементом содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

SwipeView {
    id: control

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

Настройка Switch

Переключатель состоит из трёх визуальных элементов: фонового, элемента содержимого и индикатора.

import QtQuick 2.12
import QtQuick.Controls 2.12

Switch {
    id: control
    text: qsTr("Switch")

    indicator: Rectangle {
        implicitWidth: 48
        implicitHeight: 26
        x: control.leftPadding
        y: parent.height / 2 - height / 2
        radius: 13
        color: control.checked ? "#17a81a" : "#ffffff"
        border.color: control.checked ? "#17a81a" : "#cccccc"

        Rectangle {
            x: control.checked ? parent.width - width : 0
            width: 26
            height: 26
            radius: 13
            color: control.down ? "#cccccc" : "#ffffff"
            border.color: control.checked ? (control.down ? "#17a81a" : "#21be2b") : "#999999"
        }
    }

    contentItem: Text {
        text: control.text
        font: control.font
        opacity: enabled ? 1.0 : 0.3
        color: control.down ? "#17a81a" : "#21be2b"
        verticalAlignment: Text.AlignVCenter
        leftPadding: control.indicator.width + control.spacing
    }
}

Настройка SwitchDelegate

Делегат переключателя состоит из трёх визуальных элементов: фонового, элемента содержимого и индикатора.

import QtQuick 2.12
import QtQuick.Controls 2.12

SwitchDelegate {
    id: control
    text: qsTr("SwitchDelegate")
    checked: true

    contentItem: Text {
        rightPadding: control.indicator.width + control.spacing
        text: control.text
        font: control.font
        opacity: enabled ? 1.0 : 0.3
        color: control.down ? "#17a81a" : "#21be2b"
        elide: Text.ElideRight
        verticalAlignment: Text.AlignVCenter
    }

    indicator: Rectangle {
        implicitWidth: 48
        implicitHeight: 26
        x: control.width - width - control.rightPadding
        y: parent.height / 2 - height / 2
        radius: 13
        color: control.checked ? "#17a81a" : "transparent"
        border.color: control.checked ? "#17a81a" : "#cccccc"

        Rectangle {
            x: control.checked ? parent.width - width : 0
            width: 26
            height: 26
            radius: 13
            color: control.down ? "#cccccc" : "#ffffff"
            border.color: control.checked ? (control.down ? "#17a81a" : "#21be2b") : "#999999"
        }
    }

    background: Rectangle {
        implicitWidth: 100
        implicitHeight: 40
        visible: control.down || control.highlighted
        color: control.down ? "#bdbebf" : "#eeeeee"
    }
}

Настройка TabBar

Панель вкладок состоит из двух визуальных элементов: фонового и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

TabBar {
    id: control

    background: Rectangle {
        color: "#eeeeee"
    }

    TabButton {
        text: qsTr("Home")
    }
    TabButton {
        text: qsTr("Discover")
    }
    TabButton {
        text: qsTr("Activity")
    }
}

Настройка TabButton

Кнопка вкладки можно настроить аналогично кнопке.

Настройка TextArea

TextArea состоит из элемента фонового изображения.

import QtQuick 2.12
import QtQuick.Controls 2.12

TextArea {
    id: control
    placeholderText: qsTr("Enter description")

    background: Rectangle {
        implicitWidth: 200
        implicitHeight: 40
        border.color: control.enabled ? "#21be2b" : "transparent"
    }
}

Настройка TextField

TextField состоит из элемента фонового изображения.

import QtQuick 2.12
import QtQuick.Controls 2.12

TextField {
    id: control
    placeholderText: qsTr("Enter description")

    background: Rectangle {
        implicitWidth: 200
        implicitHeight: 40
        color: control.enabled ? "transparent" : "#353637"
        border.color: control.enabled ? "#21be2b" : "transparent"
    }
}

Настройка ToolBar

ToolBar состоит из одного визуального элемента: фонового изображения.

ToolBar {
    id: control

    background: Rectangle {
        implicitHeight: 40
        color: "#eeeeee"

        Rectangle {
            width: parent.width
            height: 1
            anchors.bottom: parent.bottom
            color: "transparent"
            border.color: "#21be2b"
        }
    }

    RowLayout {
        anchors.fill: parent
        ToolButton {
            text: qsTr("Undo")
        }
        ToolButton {
            text: qsTr("Redo")
        }
    }
}

Настройка ToolButton

ToolButton состоит из двух визуальных элементов: фонового изображения и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

ToolButton {
    id: control
    text: qsTr("ToolButton")
    width: 120

    contentItem: Text {
        text: control.text
        font: control.font
        opacity: enabled ? 1.0 : 0.3
        color: control.down ? "#17a81a" : "#21be2b"
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
        elide: Text.ElideRight
    }

    background: Rectangle {
        implicitWidth: 40
        implicitHeight: 40
        color: Qt.darker("#33333333", control.enabled && (control.checked || control.highlighted) ? 1.5 : 1.0)
        opacity: enabled ? 1 : 0.3
        visible: control.down || (control.enabled && (control.checked || control.highlighted))
    }
}

Настройка ToolSeparator

ToolSeparator состоит из двух визуальных элементов: фонового изображения и элемента содержимого.

ToolBar {
    RowLayout {
        anchors.fill: parent

        ToolButton {
            text: qsTr("Action 1")
        }
        ToolButton {
            text: qsTr("Action 2")
        }

        ToolSeparator {
            padding: vertical ? 10 : 2
            topPadding: vertical ? 2 : 10
            bottomPadding: vertical ? 2 : 10

            contentItem: Rectangle {
                implicitWidth: parent.vertical ? 1 : 24
                implicitHeight: parent.vertical ? 24 : 1
                color: "#c3c3c3"
            }
        }

        ToolButton {
            text: qsTr("Action 3")
        }
        ToolButton {
            text: qsTr("Action 4")
        }

        Item {
            Layout.fillWidth: true
        }
    }
}

Настройка ToolTip

ToolTip состоит из двух визуальных элементов: фонового изображения и элемента содержимого.

import QtQuick 2.12
import QtQuick.Controls 2.12

ToolTip {
    id: control
    text: qsTr("A descriptive tool tip of what the button does")

    contentItem: Text {
        text: control.text
        font: control.font
        color: "#21be2b"
    }

    background: Rectangle {
        border.color: "#21be2b"
    }
}

Настройка Tumbler

Tumbler состоит из трёх визуальных элементов: фонового изображения, contentItem и delegate.

import QtQuick 2.12
import QtQuick.Controls 2.12

Tumbler {
    id: control
    model: 15

    background: Item {
        Rectangle {
            opacity: control.enabled ? 0.2 : 0.1
            border.color: "#000000"
            width: parent.width
            height: 1
            anchors.top: parent.top
        }

        Rectangle {
            opacity: control.enabled ? 0.2 : 0.1
            border.color: "#000000"
            width: parent.width
            height: 1
            anchors.bottom: parent.bottom
        }
    }

    delegate: Text {
        text: qsTr("Item %1").arg(modelData + 1)
        font: control.font
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
        opacity: 1.0 - Math.abs(Tumbler.displacement) / (control.visibleItemCount / 2)
    }

    Rectangle {
        anchors.horizontalCenter: control.horizontalCenter
        y: control.height * 0.4
        width: 40
        height: 1
        color: "#21be2b"
    }

    Rectangle {
        anchors.horizontalCenter: control.horizontalCenter
        y: control.height * 0.6
        width: 40
        height: 1
        color: "#21be2b"
    }
}

Если вы хотите определить свой собственный элемент содержимого, используйте ListView или PathView в качестве корневого элемента. Для обертывающего Tumbler используйте PathView:

Tumbler {
    id: tumbler

    contentItem: PathView {
        id: pathView
        model: tumbler.model
        delegate: tumbler.delegate
        clip: true
        pathItemCount: tumbler.visibleItemCount + 1
        preferredHighlightBegin: 0.5
        preferredHighlightEnd: 0.5
        dragMargin: width / 2

        path: Path {
            startX: pathView.width / 2
            startY: -pathView.delegateHeight / 2
            PathLine {
                x: pathView.width / 2
                y: pathView.pathItemCount * pathView.delegateHeight - pathView.delegateHeight / 2
            }
        }

        property real delegateHeight: tumbler.availableHeight / tumbler.visibleItemCount
    }
}

Для необорачивающего Tumbler используйте ListView:

Tumbler {
    id: tumbler

    contentItem: ListView {
        model: tumbler.model
        delegate: tumbler.delegate

        snapMode: ListView.SnapToItem
        highlightRangeMode: ListView.StrictlyEnforceRange
        preferredHighlightBegin: height / 2 - (height / tumbler.visibleItemCount / 2)
        preferredHighlightEnd: height / 2 + (height / tumbler.visibleItemCount / 2)
        clip: true
    }
}

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.14/qtquickcontrols2-customize.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API