Sur cette page

Personnalisation des contrôles Qt Quick

Qt Quick Les contrôles consistent en une hiérarchie (arbre) d'éléments. Afin d'obtenir un aspect et une convivialité personnalisés, l'implémentation QML par défaut de chaque élément peut être remplacée par une implémentation personnalisée.

Personnalisation d'un contrôle

Il arrive que vous souhaitiez créer une apparence "unique" pour une partie spécifique de votre interface utilisateur et utiliser un style complet partout ailleurs. Vous êtes peut-être satisfait du style que vous utilisez, mais il y a un bouton qui a une signification particulière.

La première façon de créer ce bouton est de le définir sur place, là où il est nécessaire. Par exemple, vous n'êtes peut-être pas satisfait des coins carrés du bouton du style Basique. Pour les arrondir, vous pouvez remplacer l'élément background et définir la propriété de rayon 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
        }
    }
}

Remarque : comme les différents éléments qui composent un contrôle dans un style donné sont conçus pour fonctionner ensemble, il peut être nécessaire de remplacer d'autres éléments pour obtenir l'aspect souhaité. En outre, tous les styles ne peuvent pas être personnalisés. Voir la note dans la référence de personnalisation pour plus d'informations.

La deuxième façon de créer le bouton est intéressante si vous prévoyez d'utiliser votre bouton arrondi à plusieurs endroits. Elle consiste à déplacer le code dans son propre fichier QML au sein de votre projet.

Pour cette approche, nous copierons le code de l'arrière-plan à partir du fichier Button.qml du style Basic. Ce fichier se trouve dans le chemin suivant de votre installation Qt :

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

Après avoir fait cela, nous ajouterons simplement la ligne suivante :

radius: 4

Pour éviter toute confusion avec les contrôles du module lui-même, nous appellerons le fichier MyButton.qml. Pour utiliser le contrôle dans votre application, référez-vous à lui par son nom de fichier :

import QtQuick.Controls.Basic

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

La troisième façon de créer le bouton est un peu plus structurée, à la fois en termes d'emplacement du fichier dans le système de fichiers et de la façon dont il est utilisé dans QML. Tout d'abord, copiez un fichier existant comme vous l'avez fait ci-dessus, mais cette fois-ci, placez-le dans un sous-dossier de votre projet nommé (par exemple) controls. Pour utiliser le contrôle, importez d'abord le dossier dans un espace de noms :

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

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

Comme vous disposez maintenant de l'espace de noms MyControls, vous pouvez nommer les contrôles d'après leurs équivalents réels dans le module Qt Quick Controls. Vous pouvez répéter ce processus pour tout contrôle que vous souhaitez ajouter.

Un avantage supplémentaire de ces trois méthodes est qu'il n'est pas nécessaire d'implémenter le modèle à partir de zéro.

Remarque : les trois approches mentionnées ici ne fonctionnent pas pour la personnalisation de la pièce jointe ToolTip, car il s'agit d'un élément partagé créé en interne. Pour une personnalisation unique d'un ToolTip, voir Custom Tool Tips. Pour personnaliser le document joint ToolTip, il doit être fourni dans le cadre de votre propre style.

Création d'un style personnalisé

Il existe plusieurs façons de créer vos propres styles. Nous expliquons ci-dessous les différentes approches.

Définition d'un style

Dans Qt Quick Controls, un style est essentiellement un ensemble de fichiers QML dans un seul répertoire. Pour qu'un style soit utilisable, quatre conditions doivent être remplies :

  • Il doit exister au moins un fichier QML dont le nom correspond à un contrôle (par exemple, Button.qml).
  • Chaque fichier QML doit contenir le type correspondant de l'importation QtQuick.Templates en tant qu'élément racine. Par exemple, Button.qml doit contenir un modèle Button comme élément racine.

    Si nous utilisions à la place le type correspondant de l'importation QtQuick.Controls comme nous l'avons fait dans la section précédente, cela ne fonctionnerait pas : le contrôle que nous définissons essaierait de dériver de lui-même.

  • Un fichier qmldir doit exister avec le(s) fichier(s) QML. Voici un exemple de fichier qmldir simple pour un style qui fournit un bouton :
    module MyStyle
    Button 2.15 Button.qml

    Si vous utilisez la sélection de style à la compilation, le qmldir doit également importer le style de repli :

    # ...
    import QtQuick.Controls.Basic auto

    Cela peut également être fait pour la sélection de style au moment de l'exécution au lieu d'utiliser, par exemple, QQuickStyle::setFallbackStyle().

    La structure du répertoire pour un tel style ressemble à ceci :

    MyStyle
    ├─── Button.qml
    └─── qmldir
  • Les fichiers doivent se trouver dans un répertoire accessible via le chemin d'importation QML.

    Par exemple, si le chemin d'accès au répertoire MyStyle mentionné ci-dessus est /home/user/MyApp/MyStyle, alors /home/user/MyApp doit être ajouté au chemin d'importation QML.

    Pour utiliser MyStyle dans MyApp, il faut le désigner par son nom :

    • ./MyApp -style MyStyle

    Le nom du style doit correspondre à la casse du répertoire de style ; passer mystyle ou MYSTYLE n'est pas supporté.

Par défaut, le système de style utilise le style Basic comme solution de repli pour les contrôles qui ne sont pas implémentés. Pour personnaliser ou étendre tout autre style intégré, il est possible de spécifier un style de repli différent à l'aide de QQuickStyle.

Cela signifie que vous pouvez implémenter autant de contrôles que vous le souhaitez pour votre style personnalisé et les placer presque n'importe où. Cela permet également aux utilisateurs de créer leurs propres styles pour votre application.

Prévisualisation des styles personnalisés dans Qt Quick Designer

En utilisant l'approche ci-dessus, il est possible de prévisualiser un style personnalisé dans Qt Quick Designer. Pour ce faire, assurez-vous que le projet possède un fichier qtquickcontrols2.conf et que l'entrée suivante existe :

[Controls]
Style=MyStyle

Pour plus d'informations, consultez l'exemple Flat Style.

Extensions C++ spécifiques au style

Il peut arriver que vous ayez besoin d'utiliser le langage C++ pour étendre votre style personnalisé.

  • Si le style qui utilise le type est le seul style utilisé par une application, enregistrez le type auprès du moteur QML en ajoutant la macro QML_ELEMENT et en intégrant le fichier à votre module 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

    Si l'en-tête dans lequel la classe est déclarée n'est pas accessible à partir du chemin d'inclusion de votre projet, vous devrez peut-être modifier le chemin d'inclusion pour que le code d'enregistrement généré puisse être compilé.

    INCLUDEPATH += MyItems

    Voir Définir les types QML à partir de C++ et Construire une application QML pour plus d'informations.

  • Si le style qui utilise le type est l'un des nombreux styles utilisés par une application, envisagez de placer chaque style dans un module distinct. Les modules seront alors chargés à la demande.

Considérations relatives aux styles personnalisés

Lorsque vous mettez en œuvre votre propre style et que vous personnalisez les contrôles, il convient de garder à l'esprit certains points afin de garantir que votre application est aussi performante que possible.

Évitez d'attribuer un identifiant aux implémentations des délégués d'éléments des styles

Comme expliqué dans Définition d'un style, lorsque vous implémentez votre propre style pour un contrôle, vous commencez par le modèle correspondant à ce contrôle. Par exemple, le site Button.qml d'un style sera structuré de la même manière :

T.Button {
    // ...

    background: Rectangle {
        // ...
    }

    contentItem: Text {
        // ...
    }

    // ...
}

Lorsque vous utilisez un bouton dans votre application, les éléments background et contentItem sont créés et rattachés à l'élément racine Button:

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

Supposons que vous ayez ensuite besoin de personnaliser le bouton une seule fois (comme expliqué dans la section Personnalisation d'un contrôle) :

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

En QML, cela entraînerait normalement la création de l'implémentation par défaut background et des éléments personnalisés background. Qt Quick Les contrôles utilisent une technique qui évite de créer les deux éléments et ne crée que l'élément personnalisé background, ce qui améliore considérablement les performances de création des contrôles.

Cette technique repose sur l'absence d'identifiant dans l'implémentation du style de cet élément. Si un identifiant est attribué, la technique ne peut pas fonctionner et les deux éléments seront créés. Par exemple, il peut être tentant d'attribuer un identifiant à background ou contentItem afin que d'autres objets du fichier puissent faire référence à ces éléments :

T.Button {
    // ...

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

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

    // ...
}

Avec ce code, chaque fois qu'une instance de bouton avec un arrière-plan personnalisé est créée, les deux arrière-plans seront créés, ce qui se traduit par des performances de création sous-optimales.

Avant Qt 5.15, l'ancien arrière-plan inutilisé était supprimé pour libérer les ressources qui lui étaient associées. Cependant, comme le contrôle ne possède pas les éléments, il ne doit pas les supprimer. Depuis Qt 5.15, les anciens éléments ne sont plus supprimés, et l'élément backgroundRect vivra donc plus longtemps que nécessaire, généralement jusqu'à ce que l'application se termine. Bien que l'ancien élément soit caché, visuellement non apparenté au contrôle et supprimé de l'arbre d'accessibilité, il est important de garder à l'esprit le temps de création et l'utilisation de la mémoire de ces éléments inutilisés lors de l'attribution d'un identifiant dans ce contexte.

Éviter les affectations impératives d'éléments personnalisés

La technique mentionnée dans la section ci-dessus ne fonctionne que lorsqu'un élément est assigné de manière déclarative pour la première fois, et les assignations impératives se traduiront par des éléments orphelins. Utilisez toujours des liens déclaratifs pour assigner des éléments personnalisés lorsque c'est possible.

Ne pas importer QtQuick.Controls dans les implémentations QML

Lorsque vous écrivez le QML pour l'implémentation d'un contrôle dans votre style, il est important de ne pas importer QtQuick.Controls. Cela empêchera le QML d'être compilé par le compilateur QML.

Implémenter des types utilisés par d'autres types

Supposons que vous utilisiez des ScrollViews dans votre application et que vous souhaitiez personnaliser leurs barres de défilement. Il est tentant d'implémenter un ScrollBar.qml personnalisé et de faire en sorte que ScrollView reprenne automatiquement le ScrollBar personnalisé. Cependant, cela ne fonctionnera pas. Vous devez implémenter à la fois ScrollBar.qml et ScrollView.qml.

Propriétés attachées

Il est courant qu'un style ait certaines propriétés ou certains attributs qui s'appliquent à tous les contrôles. Les propriétés attachées sont un excellent moyen d'étendre un élément en QML sans avoir à modifier un C++ existant appartenant à cet élément. Par exemple, les styles Material et Universal ont tous deux une propriété attachée theme qui contrôle si un élément et ses enfants seront rendus dans un thème clair ou foncé.

À titre d'exemple, ajoutons une propriété attachée qui contrôle l'élévation. Notre style illustrera l'élévation par une ombre portée ; plus l'élévation est élevée, plus l'ombre est grande.

La première étape consiste à créer une nouvelle application Qt Quick Controls dans Qt Creator. Ensuite, nous ajoutons un type C++ qui stocke l'élévation. Étant donné que ce type sera utilisé pour chaque contrôle pris en charge par notre style, et que nous pourrions souhaiter ajouter d'autres propriétés attachées ultérieurement, nous l'appellerons MyStyle. Voici 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();
}

Le type MyStyle est spécial dans le sens où il ne doit pas être instancié, mais plutôt utilisé pour ses propriétés attachées. Pour cette raison, nous l'enregistrons de la manière suivante dans 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();
}

Nous copions ensuite Button.qml du style Basic dans $QTDIR/qml/QtQuick/Controls/Basic/ dans un nouveau dossier myproject dans notre répertoire de projet. Nous ajoutons la nouvelle copie de Button.qml à qml.qrc, qui est le fichier de ressources contenant nos fichiers QML.

Ensuite, nous ajoutons une ombre portée au délégué background du bouton :

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

Notez que nous :

  • Nous n'avons pas besoin d'utiliser l'ombre portée lorsque l'élévation est de 1,5 m. 0
  • changeons la couleur de l'ombre selon que le bouton a ou non le focus
  • La taille de l'ombre dépend de l'élévation.

Pour tester la propriété attached, nous créons un site Row avec deux boutons dans main.qml:

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

L'un des boutons n'a pas d'élévation et l'autre a une élévation de 10.

Une fois ces éléments en place, nous pouvons exécuter notre exemple. Pour indiquer à l'application d'utiliser notre nouveau style, nous passons -style MyStyle comme argument d'application, mais il existe de nombreuses façons de spécifier le style à utiliser.

Le résultat final :

Boutons personnalisés

Notez que la déclaration import MyStyle 1.0 n'est nécessaire que parce que nous utilisons la propriété attachée appartenant à MyStyle. Les deux boutons utiliseront notre style personnalisé, même si nous supprimons l'importation.

Référence de personnalisation

Les extraits suivants présentent des exemples où les contrôles du style Basic ont été personnalisés en utilisant la même approche que celle décrite dans la section Personnaliser un contrôle. Le code peut être utilisé comme point de départ pour mettre en œuvre une apparence personnalisée.

Note : Les styles macOS et Windows ne sont pas adaptés à la personnalisation. Il est recommandé de toujours baser un contrôle personnalisé sur un style unique disponible sur toutes les plateformes, par exemple Style de base, Style Fusion, Style Imagine, Style Matériel, Style Universel. Ce faisant, vous avez la garantie que le contrôle aura toujours la même apparence, quel que soit le style avec lequel l'application est exécutée. Pour savoir comment utiliser un style différent, voir Utilisation des styles dans les contrôles Qt Quick . Vous pouvez également créer votre propre style.

Personnaliser ApplicationWindow

ApplicationWindow se compose d'un élément visuel : background.

import QtQuick
import QtQuick.Controls.Basic

ApplicationWindow {
    visible: true

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

Personnaliser BusyIndicator

BusyIndicator se compose de deux éléments visuels : background et contentItem.

Indicateur d'activité personnalisé

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

Personnalisation du bouton

Button se compose de deux éléments visuels : background et contentItem.

Bouton personnalisé

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

Personnalisation de CheckBox

CheckBox se compose de trois éléments visuels : background, contentItem et indicator.

Case à cocher personnalisée

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

Personnalisation de CheckDelegate

CheckDelegate se compose de trois éléments visuels : background, contentItem et indicator.

Délégué de contrôle personnalisé

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

Personnalisation de ComboBox

ComboBox se compose de background, contentItem, popup, indicator et delegate.

Boîte combo personnalisée

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

Comme expliqué dans ComboBox Model Roles, ComboBox prend en charge plusieurs types de modèles.

Étant donné que tous les modèles fournissent une propriété anonyme avec modelData, l'expression suivante récupère le bon texte dans tous les cas :

text: model[control.textRole]

Lorsque vous fournissez un textRole spécifique et un modèle avec des données structurées qui fournissent le rôle sélectionné, cette expression est une recherche de propriété régulière. Lorsque vous fournissez un modèle avec des données singulières, telles qu'une liste de chaînes, et un textRole vide, cette expression récupère le modelData.

Personnalisation de DelayButton

DelayButton se compose de deux éléments visuels : background et contentItem.

Bouton de retard personnalisé

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

Personnalisation de Dial

Dial se compose de deux éléments visuels : background et handle.

Cadran personnalisé

import QtQuick
import QtQuick.Controls.Basic

Dial {
    id: control
    background: Rectangle {
        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: 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
            }
        ]
    }
}

Personnalisation de DoubleSpinBox

DoubleSpinBox peut être personnalisé de la même manière que le bouton.

Personnalisation du tiroir

Le tiroir peut avoir un élément visuel background.

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

Personnalisation du cadre

Frame se compose d'un élément visuel : background.

Cadre personnalisé

import QtQuick
import QtQuick.Controls.Basic

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

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

Personnalisation de GroupBox

GroupBox se compose de deux éléments visuels : background et label.

Boîte de groupe personnalisée

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

Personnalisation de ItemDelegate

ItemDelegate se compose de deux éléments visuels : background et contentItem.

Délégué à l'élément stylé personnalisé

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

Personnalisation de l'étiquette

L'étiquette peut comporter un élément visuel background.

Étiquette personnalisée

import QtQuick
import QtQuick.Controls.Basic

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

Personnalisation du menu

Menu personnalisé

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

Personnalisation de la barre de menu

MenuBar peut avoir un élément visuel background et MenuBarItem se compose de deux éléments visuels : background et contentItem.

Barre de menu personnalisée avec menus Fichier et Édition

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

Personnalisation de PageIndicator

PageIndicator se compose d'un élément background, contentItem, et delegate.

Indicateur de page personnalisé affichant plusieurs pages

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

Personnalisation du volet

Le volet se compose d'un élément background.

Volet personnalisé avec arrière-plan décoratif

import QtQuick
import QtQuick.Controls.Basic

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

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

Personnalisation du Popup

Popup se compose de background et contentItem.

Popup personnalisé avec bordure et ombre

import QtQuick
import QtQuick.Controls.Basic

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

Personnalisation de la barre de progression

ProgressBar se compose de deux éléments visuels : background et contentItem.

Barre de progression personnalisée indiquant l'achèvement partiel

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

Ci-dessus, l'élément contentItem est également animé pour représenter l'état de la barre de progression indeterminate.

Personnalisation de RadioButton

RadioButton se compose de trois éléments visuels : background contentItem et indicator.

Bouton radio personnalisé dans l'état sélectionné

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

Personnalisation de RadioDelegate

RadioDelegate se compose de trois éléments visuels : background, contentItem et indicator.

Délégué radio personnalisé dans une liste

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

Personnalisation de RangeSlider

RangeSlider se compose de trois éléments visuels : background, first.handle et second.handle.

Slider de gamme personnalisé

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

Personnalisation de RoundButton

RoundButton peut être personnalisé de la même manière que le bouton.

Personnalisation de ScrollBar

ScrollBar se compose de deux éléments visuels : background et contentItem.

Barre de défilement personnalisée

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

Personnalisation de ScrollIndicator

ScrollIndicator se compose de deux éléments visuels : background et contentItem.

Indicateur de défilement personnalisé

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

Personnalisation de ScrollView

ScrollView se compose d'un élément background et de barres de défilement horizontales et verticales.

Vue de défilement personnalisée

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

Personnalisation de Slider

Slider se compose de deux éléments visuels : background, et handle.

Slider personnalisé

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

Personnalisation de SpinBox

SpinBox se compose de quatre éléments visuels : background, contentItem, up indicator, et down indicator.

Boîte à outils personnalisée

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

Personnalisation de SplitView

SplitView consiste en un délégué visuel handle.

Vue divisée personnalisée

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

Personnaliser StackView

StackView peut avoir un élément visuel background et permet de personnaliser les transitions utilisées pour les opérations de poussée, de sortie et de remplacement.

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

Personnaliser SwipeDelegate

SwipeDelegate se compose de six éléments visuels : background, contentItem, indicator, swipe.left, swipe.right, et swipe.behind.

Délégué au swipe stylisé personnalisé

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

Personnalisation de SwipeView

SwipeView peut avoir un élément visuel background. La navigation est mise en œuvre par le site contentItem.

import QtQuick
import QtQuick.Controls.Basic

SwipeView {
    id: control

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

Personnalisation de Switch

Switch se compose de trois éléments visuels : background contentItem et indicator.

Interrupteur personnalisé

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

Personnalisation de SwitchDelegate

SwitchDelegate se compose de trois éléments visuels : background, contentItem et indicator.

Délégué d'interrupteur personnalisé

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

Personnalisation de TabBar

TabBar se compose de deux éléments visuels : background, et contentItem.

Barre d'onglets personnalisée

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

Personnalisation de TabButton

TabButton peut être personnalisé de la même manière que le bouton.

Personnalisation de TextArea

TextArea consiste en un élément background.

Zone de texte personnalisée

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

Personnalisation de TextField

TextField consiste en un élément background.

Champ de texte personnalisé

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

Personnalisation de la barre d'outils

ToolBar se compose d'un élément visuel : background.

Barre d'outils personnalisée

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

Personnalisation de ToolButton

ToolButton se compose de deux éléments visuels : background et contentItem.

Bouton d'outil personnalisé

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

Personnalisation de ToolSeparator

ToolSeparator se compose de deux éléments visuels : background et contentItem.

Séparateur d'outils personnalisé

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

Personnalisation de ToolTip

ToolTip se compose de deux éléments visuels : background et contentItem.

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

Remarque : pour personnaliser le site attached ToolTip, il doit être fourni dans le cadre de votre propre style. Pour une personnalisation unique d'un élément ToolTip, voir Custom Tool Tips.

Personnalisation du Tumbler

Le Tumbler se compose de trois éléments visuels : background, contentItem, et delegate.

Gobelet personnalisé

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

Si vous souhaitez définir votre propre contentItem, utilisez ListView ou PathView comme élément racine. Pour un Tumbler enveloppant, utilisez 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
    }
}

Pour un Tumbler non enveloppant, utilisez 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
    }
}

Personnalisation de TableViewDelegate

TableViewDelegate hérite de ItemDelegate, ce qui signifie qu'il est composé de deux éléments visuels : background et contentItem.

Vous pouvez toujours attribuer votre propre délégué d'édition personnalisé à editDelegate si vous avez des besoins autres que ceux offerts par le délégué d'édition par défaut.

Délégué de vue de tableau stylisé personnalisé

delegate: TableViewDelegate {
    id: tableCell

    checked: column === 0 ? checkBox.checked : tableView.itemAtIndex(tableView.index(row, 0)).checked
    selected: checked

    background: Item {
        Rectangle {
            anchors.fill: parent
            anchors.margins: tableCell.current ? 3 : 1
            color: tableCell.selected ? "blue" : "white"
        }

        Rectangle {
            anchors.fill: parent
            color: "transparent"
            border.color: "darkblue"
            border.width: tableCell.current ? 2 : 0
        }
    }

    contentItem: Item {
        implicitHeight: 40
        visible: !tableCell.editing

        RowLayout {
            anchors.fill: parent

            CheckBox {
                id: checkBox
                implicitWidth: height
                Layout.fillHeight: true
                checked: false
                visible: tableCell.column === 0
            }

            Text {
                Layout.leftMargin: 4
                Layout.fillWidth: true
                Layout.fillHeight: true
                verticalAlignment: Text.AlignVCenter
                color: tableCell.selected ? "white" : "black"
                text: tableCell.model.display
            }
        }
    }

    TableView.editDelegate: FocusScope {
        width: parent.width
        height: parent.height

        TableView.onCommit: {
            let qaim = tableCell.tableView.model
            if (!qaim)
                return
            const index = qaim.index(tableCell.row, tableCell.column)
            // instead of the edit role, any custom role supported by the model can be checked
            // e.g. if (!tableCell.checked || !tableCell.model.customRole)
            if (!tableCell.checked || !tableCell.model.edit)
                return
            // instead of the edit role, any custom role supported by the model can be set
            // e.g. tableCell.model.customRole = textField.text
            tableCell.model.edit = textField.text
            tableCell.model.display = textField.text
        }

        Component.onCompleted: textField.selectAll()

        TextField {
            id: textField
            anchors.fill: parent
            text: tableCell.model.edit ?? tableCell.model.display ?? ""
            focus: true
        }
    }
}

Personnalisation de HeaderViewDelegate

HeaderViewDelegate hérite de TableViewDelegate, ce qui signifie qu'il est composé de deux éléments : background et contentItem. Vous pouvez toujours les personnaliser avec des éléments arbitraires.

Délégué de l'affichage de l'en-tête stylisé personnalisé

Voici un exemple de personnalisation du délégué de la vue d'en-tête horizontale :

delegate: HorizontalHeaderViewDelegate {
    id: horizontalDelegate

    required property int index
    required property string modelData

    background: Rectangle {
        height: horizontalDelegate.height
        color: columnCheckBox.checked ? palette.highlight : palette.base
        radius: 8
    }

    contentItem: Item {
        implicitWidth: columnCheckBox.implicitWidth * 2
        implicitHeight: 40

        CheckBox {
            id: columnCheckBox
            anchors.centerIn: parent
            text: horizontalDelegate.modelData
            Component.onCompleted: checked = horizontalDelegate.index === 1
        }
    }
}

Voici un exemple de personnalisation du délégué de la vue de l'en-tête vertical :

delegate: VerticalHeaderViewDelegate {
    id: verticalDelegate

    required property int index

    background: Rectangle {
        height: verticalDelegate.height
        color: palette.base
        border.width: rowCheckBox.checked ? 2 : 0
        border.color: palette.highlight
        radius: 8
    }

    contentItem: Item {
        implicitWidth: rowCheckBox.implicitWidth * 2
        implicitHeight: 40

        CheckBox {
            id: rowCheckBox
            anchors.centerIn: parent
            text: verticalDelegate.index + 1
            Component.onCompleted: checked = verticalDelegate.index % 3 === 0
        }
    }
}

Styliser les contrôles à l'aide de StyleKit

Le module StyleKit de Qt Labs fournit un ensemble de types QML pour styliser les contrôles Qt Quick, construits sur les modèles Qt Quick. Il vous permet de définir un style visuel complet pour tous vos contrôles à partir d'un seul objet Style, y compris la prise en charge des thèmes, du style basé sur l'état et des transitions. StyleKit gère automatiquement l'implémentation du modèle sous-jacent, vous permettant de vous concentrer uniquement sur les aspects visuels tels que les couleurs, les dimensions, les bordures et les ombres.

Le module StyleKit de Qt Labs est un module d'aperçu technologique dans Qt 6.11.

© 2026 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.