カスタマイズQt Quick Controls

Qt Quick Controls はアイテムの階層(ツリー)で構成されています。カスタムのルック&フィールを提供するために、各項目のデフォルトの QML 実装をカスタムのものに置き換えることができます。

コントロールのカスタマイズ

UIの特定の部分だけ "その場限り "のルックを作成し、他の部分には完全なスタイルを使用したい場合があります。今使っているスタイルには満足しているけれど、何か特別な意味を持つボタンがあるとします。

このボタンを作成する最初の方法は、必要な場所にインプレースで定義することです。たとえば、「基本」スタイルの「ボタン」の角が四角いことに不満があるとします。角を丸くするには、background アイテムをオーバーライドして、Rectangle の半径プロパティを設定します:

import QtQuick
import QtQuick.Controls.Basic

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
        }
    }
}

注意: どのスタイルでも、コントロールを構成するさまざまなアイテムは一緒に動作するように設計されているため、目的の外観を得るには他のアイテムをオーバーライドする必要がある場合があります。また、すべてのスタイルをカスタマイズできるわけではありません。詳細については、「カスタマイズ・リファレンス」の注記を参照してください。

ボタンを作成する2つ目の方法は、丸みを帯びたボタンを複数の場所で使用する場合に適しています。この方法では、コードをプロジェクト内のQMLファイルに移動します。

この方法では、BasicスタイルのButton.qml から背景のコードをコピーします。このファイルは、Qtインストール内の以下のパスにあります:

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

その後、次の行を追加します:

radius: 4

モジュール自体のコントロールとの混同を避けるため、このファイルをMyButton.qml と呼ぶことにします。アプリケーションでコントロールを使用するには、ファイル名で参照してください:

import QtQuick.Controls.Basic

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

ボタンを作成する3つ目の方法は、ファイルがファイルシステムのどこにあるかという点でも、QMLでどのように使われるかという点でも、もう少し構造化されています。まず、上と同じように既存のファイルをコピーします。ただし、今回はプロジェクトのサブフォルダに(例えば)controls という名前で入れます。コントロールを使用するには、まずそのフォルダをネームスペースにインポートします:

import QtQuick.Controls.Basic
import "controls" as MyControls

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

これでMyControls ネームスペースができたので、Qt Quick Controls モジュールの実際の対応するものにちなんでコントロールに名前を付けることができます。追加したいコントロールがあれば、このプロセスを繰り返すことができます。

これら3つの方法の利点は、テンプレートをゼロから実装する必要がないことです。

注: ToolTip は内部的に作成された共有アイテムであるため、ここで紹介した3つのアプローチは、添付の をカスタマイズする場合には機能しません。ToolTip を単発でカスタマイズするには、Custom Tool Tips を参照してください。添付のToolTip をカスタマイズするには、独自のスタイルの一部として提供する必要があります。

カスタム・スタイルの作成

独自のスタイルを作成するには、いくつかの方法があります。以下では、様々なアプローチについて説明します。

スタイルの定義

Qt Quick Controls では、スタイルとは基本的に1つのディレクトリ内にあるQMLファイルの集合を指します。スタイルが使用可能であるためには、4つの要件があります:

  • コントロール(例えば、Button.qml )と名前が一致するQMLファイルが少なくとも1つ存在すること。
  • 各 QML ファイルは、QtQuick.Templatesインポートにある関連する型をルート項目として含んでいなければなりません。例えば、Button.qml は、Button テンプレートをルート項目として含んでいなければなりません。

    前のセクションで行ったように、QtQuick.Controlsインポートから対応する型を使用した場合、うまくいきません。

  • qmldirファイルは QML ファイルと一緒に存在しなければなりません。以下は、ボタンを提供するスタイルのシンプルなqmldir ファイルの例です:
    module MyStyle
    Button 2.15 Button.qml

    コンパイル時のスタイル選択を使用している場合、qmldirはフォールバックスタイルもインポートする必要があります:

    # ...
    import QtQuick.Controls.Basic auto

    これは、例えば、QQuickStyle::setFallbackStyle()を使用する代わりに、実行時のスタイル選択のために行うこともできます。

    このようなスタイルのディレクトリ構造は次のようになります:

    MyStyle
    ├─── Button.qml
    └─── qmldir
  • ファイルはQMLインポートパスで検索可能なディレクトリに置く必要があります。

    例えば、上記のMyStyleディレクトリへのパスが/home/user/MyApp/MyStyle であった場合、/home/user/MyApp をQMLインポートパスに追加する必要があります。

    MyAppで MyStyleを 使用するには、MyStyleを名前で参照します:

    • ./MyApp -style MyStyle

    mystyleまたはMYSTYLEを渡すことはサポートされていません。

mystyleまたはMYSTYLEを渡すことはサポートされていません。デフォルトでは、スタイリングシステムは、実装されていないコントロールのフォールバックとしてBasicスタイルを使用します。その他の組み込みスタイルをカスタマイズまたは拡張するには、QQuickStyle を使用して別のフォールバック・スタイルを指定することができます。

これが意味するのは、カスタム・スタイルのために好きなだけコントロールを実装し、ほとんどどこにでも配置できるということです。また、ユーザーがアプリケーション用に独自のスタイルを作成することもできます。

Qt Quick Designer でのカスタムスタイルのプレビュー

上記の方法を使用して、Qt Quick Designer でカスタム スタイルをプレビューできます。そのためには、プロジェクトにqtquickcontrols2.confファイルがあり、以下のエントリが存在することを確認してください:

[Controls]
Style=MyStyle

詳細については、フラットスタイルの例を参照してください。

スタイル固有のC++拡張

C++を使用してカスタムスタイルを拡張する必要がある場合があります。

  • もしその型を使用するスタイルがアプリケーションで使用される唯一のスタイルである場合は、QML_ELEMENT マクロを追加し、そのファイルをQMLモジュールの一部とすることで、QMLエンジンにその型を登録します:

    qmake#tab-qmakeヘッダーでクラスが宣言されている場合、そのクラスはQMLエンジンに登録されます。
    qt_add_qml_module(ACoolItem
        URI MyItems
        VERSION 1.0
        SOURCES
            acoolcppitem.cpp acoolcppitem.h
    )
    CONFIG += qmltypes
    QML_IMPORT_NAME = MyItems
    QML_IMPORT_MAJOR_VERSION = 1

    クラスが宣言されているヘッダがプロジェクトのインクルードパスからアクセスできない場合、生成された登録コードをコンパイルできるようにインクルードパスを修正する必要があるかもしれません。

    INCLUDEPATH += MyItems

    詳しくはC++からのQML型の定義と QMLアプリケーションのビルドを参照してください。

  • 型を使用するスタイルがアプリケーションで使用される多くのスタイルのうちの1つである場合、各スタイルを別々のモジュールに入れることを検討してください。モジュールは必要に応じてロードされます。

カスタムスタイルの考慮事項

独自のスタイルを実装してコントロールをカスタマイズする場合、アプリケーションのパフォーマンスを可能な限り向上させるために注意すべき点がいくつかあります。

スタイルのアイテム デリゲートの実装に id を割り当てないようにする。

スタイルの定義で説明したように、コントロールに独自のスタイルを実装する場合、そのコントロールに関連するテンプレートから始めます。例えば、スタイルのButton.qml は、このような構造になっています:

T.Button {
    // ...

    background: Rectangle {
        // ...
    }

    contentItem: Text {
        // ...
    }

    // ...
}

アプリケーションで Button を使用する場合、backgroundcontentItem アイテムが作成され、ルートButton アイテムの親になります:

// Creates the Button root item, the Rectangle background,
// and the Text contentItem.
Button {
    text: qsTr("Confirm")
}

アプリケーションでButtonを使用する場合、、 のアイテムが作成され、ルート アイテムの親となります。(コントロールのカスタマイズで説明したように)Buttonを単発でカスタマイズする必要があるとします:

import QtQuick
import QtQuick.Controls.Basic

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では、通常、この場合、デフォルトのbackground 実装と、単発のカスタムbackground アイテムの両方が作成されることになります。Qt Quick Controls では、両方のアイテムの作成を避け、カスタムbackground のみを作成するテクニックを採用しており、コントロールの作成パフォーマンスを大幅に向上させています。

このテクニックは、そのアイテムのスタイルの実装にid がないことに依存します。id が割り当てられると、このテクニックは機能せず、両方のアイテムが作成されます。たとえば、ファイル内の他のオブジェクトがこれらのアイテムを参照できるように、backgroundcontentItem に id を割り当てたくなることがあります:

T.Button {
    // ...

    background: Rectangle {
        id: backgroundRect
        // ...
    }

    contentItem: Text {
        // Use backgroundRect in some way...
    }

    // ...
}

このコードでは、カスタマイズされた背景を持つButtonインスタンスが作成されるたびに、両方の背景が作成されることになり、最適な作成パフォーマンスが得られません。

Qt 5.15以前では、古い未使用の背景を削除して、関連するリソースを解放していました。しかし、コントロールはアイテムを所有していないので、削除すべきではありません。Qt 5.15では、古いアイテムは削除されなくなりました。そのため、backgroundRect のアイテムは必要以上に長く、通常はアプリケーションが終了するまで生き続けることになります。古いアイテムは非表示になり、コントロールから視覚的にアンペアレントされ、アクセシビリティツリーから削除されますが、このコンテキストでidを割り当てるときは、これらの未使用アイテムの作成時間とメモリ使用量を念頭に置くことが重要です。

カスタムアイテムの命令的な割り当ては避ける

上のセクションで述べたテクニックは、アイテムが宣言的に初めて割り当てられる場合にのみ機能します。可能であれば、カスタムアイテムの割り当てには常に宣言的バインディングを使用してください。

QMLの実装でQtQuick.Controlsをインポートしない

スタイルのコントロール実装の QML を書く際には、QtQuick.Controls をインポートしないことが重要です。インポートすると、QMLコンパイラでコンパイルできなくなります。

他の型が使用する型を実装する

アプリケーションでScrollViewを使用していて、そのスクロールバーをカスタマイズしたいと思ったとします。ScrollBar.qmlを実装し、ScrollView がカスタマイズされたScrollBar を自動的にピックアップするようにしたいところです。しかし、これはうまくいきません。ScrollBar.qml ScrollView.qml の両方を実装する必要があります。

付属プロパティ

スタイルには、すべてのコントロールに適用される特定のプロパティや属性があるのが普通です。アタッチド・プロパティは、そのアイテムに属する既存のC++を変更することなく、QMLのアイテムを拡張する素晴らしい方法です。例えば、マテリアル・スタイルと ユニバーサル・スタイルには、アイテムやその子アイテムを明るいテーマで表示するか、暗いテーマで表示するかを制御するテーマ・プロパティが付属しています。

例として、高さを制御する付属プロパティを追加してみましょう。このスタイルでは、高度をドロップシャドウで表現します。高度が高いほど、シャドウは大きくなります。

最初のステップは、Qt Creator新しいQt Quick Controls アプリケーションを作成することです。その後、標高を格納する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[])
{
    QGuiApplication app(argc, argv);

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

    QQmlApplicationEngine engine;
    // Make the directory containing our style known to the QML engine.
    engine.addImportPath(":/");
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    return app.exec();
}

次に、$QTDIR/qml/QtQuick/Controls/Basic/ のBasicスタイルからButton.qml をプロジェクト・ディレクトリの新しいmyproject フォルダにコピーします。新しくコピーしたButton.qml を、QMLファイルを含むリソースファイルであるqml.qrc に追加します。

次に、Buttonのbackground デリゲートにドロップシャドウを追加します:

// ...
import QtQuick.Effects
import MyStyle
// ...

background: Rectangle {
    // ...

    layer.enabled: control.enabled && control.MyStyle.elevation > 0
    layer.effect: MultiEffect {
        shadowEnabled: true
        shadowHorizontalOffset: 3
        shadowVerticalOffset: 3
        shadowColor: control.visualFocus ? "#330066ff" : "#aaaaaa"
        shadowBlur: control.pressed ? 0.8 : 0.4
    }
}

ここで注意してください:

  • 標高が高いときは、わざわざドロップシャドウを使う必要はありません。0
  • ボタンにフォーカスがあるかどうかで、影の色を変える。
  • 影の大きさを標高に依存させる。

付属のプロパティを試すために、main.qml に2つのボタンがあるRow を作成します:

import QtQuick
import QtQuick.Controls

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
        }
    }
}

1つのボタンは標高がなく、もう1つのボタンは標高が10 です。

これでサンプルを実行できます。アプリケーションに新しいスタイルを使用するように指示するために、アプリケーションの引数として-style MyStyle を渡しますが、使用するスタイルを指定する方法はたくさんあります。

最終結果です:

MyStyle に属するアタッチされたプロパティを使用しているため、import MyStyle 1.0 ステートメントが必要なだけであることに注意してください。インポートを削除しても、両方のボタンでカスタム・スタイルが使用されます。

カスタマイズのリファレンス

以下のスニペットは、「コントロールのカスタマイズ」セクションと同じアプローチで基本スタイルのコントロールをカスタマイズした例です。このコードは、カスタムのルック&フィールを実装するための出発点として使用できます。

注意: macOSと Windowsのスタイルはカスタマイズに適していません。基本スタイルフュージョン・スタイルイマジン・スタイルマテリアル・スタイルユニバーサル・スタイルなど、すべてのプラットフォームで利用可能な単一のスタイルをベースにカスタマイズすることをお勧めします。そうすることで、アプリケーションがどのスタイルで実行されても、常に同じように見えることが保証されます。別のスタイルを使用する方法については、 Qt Quick Controls でスタイルを使用する を参照してください。また、独自のスタイルを作成することもできます。

ApplicationWindow のカスタマイズ

ApplicationWindow は1つのビジュアル・アイテムから構成されています: 。background

import QtQuick
import QtQuick.Controls.Basic

ApplicationWindow {
    visible: true

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

BusyIndicator のカスタマイズ

BusyIndicator のカスタマイズは 2 つのビジュアルアイテム と で構成されています。background contentItem

import QtQuick
import QtQuick.Controls.Basic

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 {
                    id: delegate
                    x: item.width / 2 - width / 2
                    y: item.height / 2 - height / 2
                    implicitWidth: 10
                    implicitHeight: 10
                    radius: 5
                    color: "#21be2b"

                    required property int index

                    transform: [
                        Translate {
                            y: -Math.min(item.width, item.height) * 0.5 + 5
                        },
                        Rotation {
                            angle: delegate.index / repeater.count * 360
                            origin.x: 5
                            origin.y: 5
                        }
                    ]
                }
            }
        }
    }
}

ボタンのカスタマイズ

ボタンはbackgroundcontent item の2つのビジュアルアイテムから構成されています。

import QtQuick
import QtQuick.Controls.Basic

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 は3つのビジュアル・アイテムで構成されています: と 。background contentItem indicator

import QtQuick
import QtQuick.Controls.Basic

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 には3つの視覚的な項目があります: と 。background contentItem indicator

import QtQuick
import QtQuick.Controls.Basic

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 は , , , , で構成されています。background content item popup indicator delegate

pragma ComponentBehavior: Bound

import QtQuick
import QtQuick.Controls.Basic

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

    delegate: ItemDelegate {
        id: delegate

        required property var model
        required property int index

        width: control.width
        contentItem: Text {
            text: delegate.model[control.textRole]
            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
            function 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
        height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
        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
        }
    }
}

ComboBox Model Roles で説明したように、ComboBox は複数のタイプのモデルをサポートしています。

すべてのモデルは modelData匿名プロパティを提供するので、以下の式はすべてのケースで正しいテキストを取得します:

text: model[control.textRole]

特定のtextRole 、選択された役割を提供する構造化データを持つモデルを提供する場合、この式は通常のプロパティ検索です。文字列のリストのような特異なデータを持つモデルと空のtextRole を提供する場合、この式はmodelData を検索します。

DelayButtonのカスタマイズ

DelayButton は、 と の2つのビジュアル・アイテムから構成されています。background content item

import QtQuick
import QtQuick.Controls.Basic

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
                function 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()
            }
        }
    }
}

ダイヤルのカスタマイズ

ダイヤルは、backgroundhandle の2つのビジュアルアイテムで構成されています。

インポート QtQuickインポート QtQuick.Controls.BasicDial{id:control background長方形{x:control.width / 2 - width / 2 y:control.height / 2 - height / 2 implicitWidth:140 implicitHeight:140 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矩形{id:handleItemx: control.background.x + control.background.width / 2 - width / 2y: control.background.y + control.background.height / 2 - height / 2 width:16 height:16 color:control.pressed?"#17a81a":"#21be2b" radius:8 アンチエイリアス: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} } }

引き出しのカスタマイズ

ドロワーは、ビジュアルbackground アイテムを持つことができます。

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

フレームのカスタマイズ

フレームは1つのビジュアルアイテムで構成されます:background

import QtQuick
import QtQuick.Controls.Basic

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

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

グループボックスのカスタマイズ

GroupBox は、 と の2つのビジュアル・アイテムで構成されます。background label

import QtQuick
import QtQuick.Controls.Basic

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のカスタマイズ

ItemDelegate は、 と の2つのビジュアル・アイテムから構成されています。background content item

import QtQuick
import QtQuick.Controls.Basic

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
        }
    }
}

ラベルのカスタマイズ

ラベルはビジュアル項目background を持つことができます。

import QtQuick
import QtQuick.Controls.Basic

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

メニューのカスタマイズ

import QtQuick
import QtQuick.Controls.Basic

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
    }
}

メニューバーのカスタマイズ

MenuBar にはビジュアルな アイテムがあり、 は と の2つのビジュアル・アイテムで構成されています。background MenuBarItem background content item

import QtQuick
import QtQuick.Controls.Basic

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のカスタマイズ

PageIndicator は、 、 、 で構成されています。background content item delegate

import QtQuick
import QtQuick.Controls.Basic

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

        required property int index

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

ペインのカスタマイズ

ペインはbackground で構成されている。

import QtQuick
import QtQuick.Controls.Basic

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

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

ポップアップのカスタマイズ

ポップアップはbackgroundcontent item で構成される。

import QtQuick
import QtQuick.Controls.Basic

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

プログレスバーのカスタマイズ

ProgressBar は、 と の2つのビジュアル・アイテムで構成されています。background content item

import QtQuick
import QtQuick.Controls.Basic

ProgressBar {
    id: control
    value: 0.5
    padding: 2

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

    contentItem: Item {
        implicitWidth: 200
        implicitHeight: 4

        // Progress indicator for determinate state.
        Rectangle {
            width: control.visualPosition * parent.width
            height: parent.height
            radius: 2
            color: "#17a81a"
            visible: !control.indeterminate
        }

        // Scrolling animation for indeterminate state.
        Item {
            anchors.fill: parent
            visible: control.indeterminate
            clip: true

            Row {
                spacing: 20

                Repeater {
                    model: control.width / 40 + 1

                    Rectangle {
                        color: "#17a81a"
                        width: 20
                        height: control.height
                    }
                }
                XAnimator on x {
                    from: 0
                    to: -40
                    loops: Animation.Infinite
                    running: control.indeterminate
                }
            }
        }
    }
}

上記では、indeterminate プログレスバーの状態を表現するために、コンテンツアイテムもアニメーションしています。

ラジオボタンのカスタマイズ

RadioButton は3つのビジュアル・アイテムから構成されています: と 。background content item indicator

import QtQuick
import QtQuick.Controls.Basic

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のカスタマイズ

RadioDelegate は3つのビジュアル・アイテムで構成されています: と 。background contentItem indicator

import QtQuick
import QtQuick.Controls.Basic

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のカスタマイズ

RangeSlider は3つのビジュアル・アイテムから構成されています: と 。background first.handle second.handle

import QtQuick
import QtQuick.Controls.Basic

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のカスタマイズ

RoundButtonButtonと同様にカスタマイズできます。

スクロールバーのカスタマイズ

ScrollBar は と の2つのビジュアルアイテムから構成されます。background content item

import QtQuick
import QtQuick.Controls.Basic

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"
        // Hide the ScrollBar when it's not needed.
        opacity: control.policy === ScrollBar.AlwaysOn || (control.active && control.size < 1.0) ? 0.75 : 0

        // Animate the changes in opacity (default duration is 250 ms).
        Behavior on opacity {
            NumberAnimation {}
        }
    }
}

ScrollIndicator

ScrollIndicator は と の 2 つのビジュアルアイテムで構成されます。background content item

import QtQuick
import QtQuick.Controls.Basic

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

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

ScrollView のカスタマイズ

ScrollView は、 アイテムと、水平および垂直スクロールバーで構成されます。background

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"
    }
}

スライダーのカスタマイズ

スライダーは2つのビジュアルアイテムで構成されます:backgroundhandle

import QtQuick
import QtQuick.Controls.Basic

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 は4つのビジュアル・アイテムで構成されています: 、 、 。background contentItem up indicator down indicator

import QtQuick
import QtQuick.Controls.Basic

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 は、 のビジュアルデリゲートから構成されています。handle

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のカスタマイズ

StackView はビジュアルな アイテムを持つことができ、push、pop、replace 操作に使用されるトランジションをカスタマイズできます。background

import QtQuick
import QtQuick.Controls.Basic

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のカスタマイズ

SwipeDelegate は6つのビジュアル・アイテムから構成されています: , , , , 。background content item indicator swipe.left swipe.right swipe.behind

import QtQuick
import QtQuick.Controls.Basic

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のカスタマイズ

SwipeView は、 のビジュアル・アイテムを持つことができます。ナビゲーションは によって実装されます。background content item

import QtQuick
import QtQuick.Controls.Basic

SwipeView {
    id: control

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

スイッチのカスタマイズ

Switchは3つのビジュアル・アイテムで構成されています:background content itemindicator

import QtQuick
import QtQuick.Controls.Basic

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のカスタマイズ

SwitchDelegate は3つのビジュアル・アイテムで構成されている: と 。background contentItem indicator

import QtQuick
import QtQuick.Controls.Basic

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 は2つのビジュアル・アイテムで構成されています:と 。background contentItem

import QtQuick
import QtQuick.Controls.Basic

TabBar {
    id: control

    background: Rectangle {
        color: "#eeeeee"
    }

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

タブボタンのカスタマイズ

TabButtonButtonと同様にカスタマイズできます。

テキストエリアのカスタマイズ

TextArea は 。background

import QtQuick
import QtQuick.Controls.Basic

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

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

TextFieldのカスタマイズ

TextField background

import QtQuick
import QtQuick.Controls.Basic

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 はひとつの視覚的なアイテムから構成されています: 。background

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 は、 と の 2 つのビジュアルアイテムで構成されます。background content item

import QtQuick
import QtQuick.Controls.Basic

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 は、 と の2つのビジュアルアイテムで構成されています。background content item

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 は、 と の2つのビジュアル・アイテムで構成されています。background content item

import QtQuick
import QtQuick.Controls.Basic

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"
    }
}

注: attached ToolTip をカスタマイズするには、独自のスタイルの一部として提供する必要があります。ToolTip を単発的にカスタマイズするには、Custom Tool Tips を参照してください。

タンブラーのカスタマイズ

タンブラーは3つのビジュアルアイテムで構成されています:background contentItemdelegate

import QtQuick
import QtQuick.Controls.Basic

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)

        required property var modelData
        required property int index
    }

    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"
    }
}

独自のcontentItemを定義したい場合は、ListView またはPathView をルートアイテムとして使用します。ラッピング・タンブラーには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
    }
}

ラッピングなしのタンブラーには、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
    }
}

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.