사용자 지정 Qt Quick Controls
Qt Quick Controls 항목들의 계층 구조(트리)로 구성됩니다. 사용자 정의된 모양과 느낌을 제공하기 위해, 각 항목의 기본 QML 구현을 사용자 정의 구현으로 대체할 수 있습니다.
컨트롤 사용자 정의
때로는 UI의 특정 부분에 대해 “단 한 번만 적용되는” 디자인을 만들고, 나머지 부분에는 동일한 스타일을 적용하고 싶을 때가 있습니다. 현재 사용 중인 스타일에는 만족하지만, 특별한 의미를 지닌 특정 버튼이 있을 수도 있습니다.
이러한 버튼을 만드는 첫 번째 방법은 필요한 위치에서 바로 정의하는 것입니다. 예를 들어, 기본 스타일의 버튼 모서리가 사각형인 것이 마음에 들지 않을 수 있습니다. 모서리를 둥글게 만들려면 ` background ` 항목을 재정의하고 `Rectangle`의 `radius` 속성을 설정하면 됩니다:
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 파일로 옮기는 과정을 포함합니다.
이 방법을 사용하려면 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")
}
}버튼을 생성하는 세 번째 방법은 파일 시스템 내 파일의 위치와 QML에서 사용하는 방식 모두에서 좀 더 체계적입니다. 먼저, 위와 같이 기존 파일을 복사하되, 이번에는 프로젝트 내의 (예를 들어) ` controls`라는 하위 폴더에 저장합니다. 이 컨트롤을 사용하려면 먼저 해당 폴더를 네임스페이스로 임포트해야 합니다:
import QtQuick.Controls.Basic
import "controls" as MyControls
ApplicationWindow {
MyControls.Button {
text: qsTr("A Special Button")
}
}이제 MyControls 네임스페이스가 생성되었으므로, Qt Quick Controls 모듈에 있는 실제 컨트롤과 동일한 이름으로 컨트롤을 지정할 수 있습니다. 추가하고자 하는 모든 컨트롤에 대해 이 과정을 반복할 수 있습니다.
이 세 가지 방법의 또 다른 장점은 템플릿을 처음부터 직접 구현할 필요가 없다는 점입니다.
참고: 여기서 언급한 세가지 방법은 첨부된 ToolTip 을 사용자 정의하는 데는 적용되지 않습니다. 이는 내부적으로 생성된 공유 항목이기 때문입니다. ToolTip 을 일회성으로 사용자 정의하려면 Custom Tool Tips 를 참조하십시오. 첨부된 ToolTip 을 사용자 정의하려면 이를 사용자 정의 스타일의 일부로 제공해야 합니다.
사용자 정의 스타일 만들기
사용자 정의 스타일을 생성하는 방법에는 여러 가지가 있습니다. 아래에서는 다양한 접근 방식을 설명하겠습니다.
스타일 정의
Qt Quick Controls 에서 스타일은 기본적으로 단일 디렉토리 내에 있는 QML 파일들의 집합입니다. 스타일을 사용할 수 있으려면 다음 네 가지 조건이 충족되어야 합니다:
- 컨트롤 이름(예:
Button.qml)과 일치하는 QML 파일이 적어도 하나 존재해야 합니다. - 각 QML 파일은 루트 항목으로 QtQuick.Templates 임포트에서 가져온 관련 타입을 포함해야 합니다. 예를 들어, Button.qml은 루트 항목으로 Button 템플릿을 포함해야 합니다.
만약 이전 섹션에서 했던 것처럼 QtQuick.Controls 임포트에서 해당 타입을 대신 사용했다면, 정의 중인 컨트롤이 스스로를 상속하려고 시도하게 되어 작동하지 않을 것입니다.
- QML 파일과 함께 qmldir 파일이 반드시 존재해야 합니다. 다음은 버튼을 제공하는 스타일을 위한 간단한
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인 경우, QML 임포트 경로에/home/user/MyApp를 추가해야 합니다.MyApp에서 MyStyle을 사용 하려면 이름으로 참조하십시오:
./MyApp -style MyStyle
스타일 이름은 스타일 디렉터리의 대소문자 구분을 정확히 따라야 하며, mystyle 또는 MYSTYLE과 같이 대소문자를 달리 표기하는 것은 지원되지 않습니다.
기본적으로 스타일링 시스템은 구현되지 않은 컨트롤에 대해 ‘Basic’ 스타일을 대체 스타일로 사용합니다. 다른 내장 스타일을 사용자 정의하거나 확장하려면 ` QQuickStyle`을 사용하여 다른 대체 스타일을 지정할 수 있습니다.
즉, 사용자 정의 스타일에 대해 원하는 만큼 많은 컨트롤을 구현하고, 이를 거의 모든 곳에 배치할 수 있습니다. 또한 사용자가 애플리케이션에 대한 자신만의 스타일을 만들 수도 있습니다.
Qt Quick Designer에서 사용자 정의 스타일 미리 보기
위의 방법을 사용하면 Qt Quick Designer에서 사용자 정의 스타일을 미리 볼 수 있습니다. 이를 위해서는 프로젝트에 qtquickcontrols2.conf 파일이 있고, 다음 항목이 포함되어 있는지 확인하십시오:
[Controls]
Style=MyStyle자세한 내용은 Flat Style 예제를 참고하십시오.
스타일별 C++ 확장 기능
때로는 사용자 정의 스타일을 확장하기 위해 C++을 사용해야 할 수도 있습니다.
- 해당 타입을 사용하는 스타일이 애플리케이션에서 유일하게 사용되는 스타일인 경우, ` QML_ELEMENT ` 매크로를 추가하고 해당 파일을 QML 모듈의 일부로 포함시켜 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 애플리케이션 빌드하기 ’를 참조하십시오.
- 해당 유형을 사용하는 스타일이 애플리케이션에서 사용하는 여러 스타일 중 하나인 경우, 각 스타일을 별도의 모듈에 배치하는 것을 고려해 보십시오. 그러면 모듈은 필요에 따라 로드됩니다.
사용자 정의 스타일에 대한 고려 사항
자신만의 스타일을 구현하고 컨트롤을 사용자 정의할 때, 애플리케이션의 성능을 최대한 보장하기 위해 유의해야 할 몇 가지 사항이 있습니다.
스타일의 항목 델리게이트 구현에 ID를 할당하지 마십시오.
'스타일 정의'에서 설명한 바와 같이, 컨트롤에 대한 사용자 정의 스타일을 구현할 때는 해당 컨트롤에 대한 관련 템플릿을 기반으로 시작합니다. 예를 들어, 스타일의 ` Button.qml `은 다음과 같이 구성됩니다.
애플리케이션에서 Button을 사용할 때, ` background ` 및 ` contentItem ` 항목이 생성되어 루트 ` Button ` 항목의 자식으로 설정됩니다:
// Creates the Button root item, the Rectangle background,
// and the Text contentItem.
Button {
text: qsTr("Confirm")
}이때 '컨트롤 사용자 정의( Customizing a Control)'에서 설명한 대로 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가 할당된 경우 이 기법은 작동하지 않으며, 두 항목이 모두 생성됩니다. 예를 들어, 파일 내의 다른 객체들이 해당 항목을 참조할 수 있도록 background 또는 contentItem 에 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 컴파일러가 해당 QML을 컴파일하지 못하게 됩니다.
다른 유형에서 사용하는 유형을 구현하십시오
애플리케이션에서 ScrollView를 사용하고 있으며, 해당 스크롤바를 사용자 정의하기로 결정했다고 가정해 보겠습니다. 단순히 사용자 정의 ScrollBar.qml을 구현하고, ScrollView 가 사용자 정의된 ScrollBar 를 자동으로 인식하도록 하는 것이 유혹적일 수 있습니다. 그러나 이 방법은 작동하지 않습니다. ScrollBar. qml과 ScrollView.qml 을 모두 구현해야 합니다.
부착 속성
스타일에는 모든 컨트롤에 적용되는 특정 속성이나 속성이 포함되는 경우가 흔합니다. 부착 속성은 해당 항목에 속한 기존 C++ 코드를 수정하지 않고도 QML에서 항목을 확장할 수 있는 훌륭한 방법입니다. 예를 들어, Material 및 Universal 스타일 모두 항목과 그 자식 요소가 밝은 테마로 렌더링될지 어두운 테마로 렌더링될지를 제어하는 ‘theme’ 부착 속성을 가지고 있습니다.
예를 들어, 높이를 제어하는 첨부 속성을 추가해 보겠습니다. 이 스타일은 드롭 섀도우를 통해 높이를 표현하며, 높이가 높을수록 그림자가 커집니다.
첫 번째 단계는 Qt Creator 또는 Qt Extension for Visual Studio Code 에서 새로운 Qt Quick Controls 애플리케이션을 생성하는 것입니다. 그 후, Qt Creator 또는 Qt Extension for Visual Studio Code 에서 고도를 저장하는 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_HMyStyle.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`에 두 개의 버튼이 포함된 ` 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
}
}
}한 버튼은 높이가 없고, 다른 버튼은 높이가 10 입니다.
이 설정이 완료되면 예제를 실행할 수 있습니다. 애플리케이션에 새로운 스타일을 사용하도록 지시하기 위해 -style MyStyle 를 애플리케이션 인수로 전달하지만, 사용할 스타일을 지정하는 방법은 여러 가지가 있습니다.
최종 결과:

import MyStyle 1.0 문은 MyStyle 에 속한 부착 속성을 사용하고 있기 때문에 필요한 것임을 유의하십시오. import 문을 제거하더라도 두 버튼 모두 사용자 정의 스타일을 사용합니다.
사용자 지정 참조
다음 코드 조각들은 ‘컨트롤 사용자 지정’ 섹션과 동일한 접근 방식을 사용하여 Basic 스타일의 컨트롤을 사용자 지정한 예시를 보여줍니다. 이 코드는 사용자 정의 모양과 느낌을 구현하기 위한 출발점으로 활용할 수 있습니다.
참고: macOS 및 Windows스타일은 사용자 정의에 적합하지 않습니다. 대신, 사용자 정의 컨트롤은 항상 모든 플랫폼에서 사용할 수 있는 단일 스타일(예: Basic Style, Fusion Style, Imagine Style, Material Style, Universal Style)을 기반으로 하는 것이 권장됩니다. 이렇게 하면 애플리케이션이 어떤 스타일로 실행되든 항상 동일한 모양을 유지할 수 있습니다. 다른 스타일을 사용하는 방법에 대해서는 Qt Quick Controls 의 ‘스타일 사용’을 참조하십시오. 또는 사용자 정의 스타일을 직접 만들 수도 있습니다.
참고: 컨트롤의 크기를 조정할때 , 실제 콘텐츠 크기는 일반적으로 동일하게 유지됩니다. 예를 들어, 일부 스타일은 버튼이 컨트롤의 경계를 채우도록 하면서도, CheckBox 의 확인 표시기와 텍스트를 가로 및/또는 세로로 중앙 정렬할 수 있습니다. 기본 크기 조정 동작이 바람직하지 않은 경우, 해당 델리게이트를 재정의하십시오.
ApplicationWindow 사용자 지정
ApplicationWindow 는 하나의 시각적 항목, 즉 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 두 개의 시각적 항목, 즉 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
}
]
}
}
}
}
}Button 사용자 지정
Button은 두 개의 시각적 항목, 즉 background 와 contentItem 로 구성됩니다.

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 사용자 지정
CheckBox 세 가지 시각적 항목( 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 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 사용자 정의
ComboBox background, , , 및 로 구성됩니다. contentItem 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 DelayButton은 ‘ background ’과 ‘ contentItem ’이라는 두 가지 시각적 항목으로 구성됩니다.

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()
}
}
}
}Dial 사용자 지정
Dial은 background 와 handle 라는 두 가지 시각적 항목으로 구성됩니다.

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
}
]
}
}DoubleSpinBox 사용자 정의
DoubleSpinBox Button과 동일한 방식으로 사용자 정의할 수 있습니다.
Drawer 사용자 지정
Drawer에는 시각적 요소인 background 를 포함할 수 있습니다.
background: Rectangle {
Rectangle {
x: parent.width - 1
width: 1
height: parent.height
color: "#21be2b"
}
}Frame 사용자 정의
Frame은 하나의 시각적 항목인 background 로 구성됩니다.

import QtQuick
import QtQuick.Controls.Basic
Frame {
background: Rectangle {
color: "transparent"
border.color: "#21be2b"
radius: 2
}
Label {
text: qsTr("Content goes here!")
}
}GroupBox 사용자 정의
GroupBox 두 개의 시각적 항목, 즉 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 두 개의 시각적 항목( background 및 contentItem)으로 구성됩니다.

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"
}메뉴 사용자 정의
- Menu background 시각적 항목으로 구성됩니다.
- MenuItem 다음 네 가지 시각적 항목으로 구성됩니다: background, contentItem, indicator 및 arrow.
- MenuSeparator background 및 시각적 항목으로 구성됩니다. contentItem

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 에는 시각적 항목인 background 이 포함될 수 있으며, MenuBarItem 은 background 와 contentItem 라는 두 가지 시각적 항목으로 구성됩니다.

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, 및 로 구성됩니다. contentItem 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
}
}
}
}Pane 사용자 지정
Pane은 background 로 구성됩니다.

import QtQuick
import QtQuick.Controls.Basic
Pane {
background: Rectangle {
color: "#eeeeee"
}
Label {
text: qsTr("Content goes here!")
}
}팝업 사용자 정의
팝업은 background 와 contentItem 로 구성됩니다.

import QtQuick
import QtQuick.Controls.Basic
Popup {
id: popup
background: Rectangle {
implicitWidth: 200
implicitHeight: 200
border.color: "#444"
}
contentItem: Column {}
}진행률 표시줄 사용자 정의
ProgressBar 두 가지 시각적 요소, 즉 ' background '과 ' contentItem'으로 구성됩니다.

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
}
}
}
}
}위에서 contentItem은 indeterminate 진행률 표시줄 상태를 나타내기 위해 애니메이션 처리됩니다.
RadioButton 사용자 정의
RadioButton 세 가지 시각적 항목, 즉 background, contentItem 및 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 는 세 가지 시각적 항목, 즉 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 는 세 가지 시각적 요소, 즉 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 사용자 정의
RoundButton 는 Button과 동일한 방식으로 사용자 정의할 수 있습니다.
ScrollBar 사용자 지정
ScrollBar background 와 , 이렇게 두 가지 시각적 항목으로 구성됩니다. contentItem

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 background 와 라는 두 가지 시각적 항목으로 구성됩니다. contentItem

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"
}
}슬라이더 사용자 지정
슬라이더는 두 가지 시각적 항목, 즉 background 와 handle 로 구성됩니다.

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 사용자 지정
SpinBox 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 은 시각적 background 항목을 가질 수 있으며, push, pop 및 replace 연산에 사용되는 전환 효과를 사용자 정의할 수 있습니다.
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 는 background, contentItem, indicator, swipe.left, swipe.right, swipe.behind 등 6개의 시각적 항목으로 구성됩니다.

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 항목이 포함될 수 있습니다. 탐색 기능은 contentItem 를 통해 구현됩니다.
import QtQuick
import QtQuick.Controls.Basic
SwipeView {
id: control
background: Rectangle {
color: "#eeeeee"
}
}Switch 사용자 정의
Switch는 background, contentItem, indicator 의 세 가지 시각적 항목으로 구성됩니다.

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 다음 세 가지 시각적 항목으로 구성됩니다: 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 사용자 정의
TabBar 두 가지 시각적 항목, 즉 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")
}
}TabButton 사용자 정의
TabButton Button과 동일한 방식으로 사용자 정의할 수 있습니다.
TextArea 사용자 정의
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 사용자 지정
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 사용자 지정
ToolButton 두 개의 시각적 항목( background 및 contentItem)으로 구성됩니다.

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 사용자 지정
ToolSeparator 두 개의 시각적 항목( background 및 contentItem)으로 구성됩니다.

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 두 가지 시각적 항목, 즉 background 와 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"
}
}참고: attached ToolTip 를 사용자정의하려면 , 이를 사용자 정의 스타일의 일부로 제공해야 합니다. ToolTip 를 일회성으로 사용자 정의하려면 Custom Tool Tips 를 참조하십시오.
Tumbler 사용자 정의
Tumbler는 background, contentItem, delegate 의 세 가지 시각적 항목으로 구성됩니다.

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 중 하나를 루트 항목으로 사용하십시오. 래핑형 Tumbler의 경우 PathView 를 사용하십시오:
Tumbler {
id: tumbler
contentItem: PathView {
id: pathView
model: tumbler.model
delegate: tumbler.delegate
clip: true
pathItemCount: tumbler.visibleItemCount + 1
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
dragMargin: width / 2
path: Path {
startX: pathView.width / 2
startY: -pathView.delegateHeight / 2
PathLine {
x: pathView.width / 2
y: pathView.pathItemCount * pathView.delegateHeight - pathView.delegateHeight / 2
}
}
property real delegateHeight: tumbler.availableHeight / tumbler.visibleItemCount
}
}줄 바꿈이 없는 텀블러를 사용하려면 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
}
}TableViewDelegate 사용자 정의
TableViewDelegate 는 ItemDelegate 를 상속받으므로, background 와 contentItem 라는 두 가지 시각적 요소로 구성됩니다.
기본 편집 델리게이트가 제공하는 기능 이외의 추가 기능이 필요한 경우, 언제든지 editDelegate 에 사용자 정의 편집 델리게이트를 할당할 수 있습니다.

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
}
}
}HeaderViewDelegate 사용자 지정
HeaderViewDelegate는 TableViewDelegate 를 상속받으므로, background 와 contentItem 라는 두 가지 항목으로 구성됩니다. 이 항목들은 언제든지 임의의 항목으로 사용자 정의할 수 있습니다.

다음은 수평 헤더 뷰 델리게이트를 사용자 정의하는 예시입니다:
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
}
}
}다음은 수직 헤더 뷰 델리게이트를 사용자 정의하는 예시입니다:
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
}
}
}StyleKit을 사용한 컨트롤 스타일 지정
Qt Labs StyleKit 모듈은 Qt Quick Templates 2를 기반으로 하여 Qt Quick Controls 의 스타일을 지정하기 위한 일련의 QML 유형을 제공합니다. 이를 통해 테마, 상태 기반 스타일링 및 전환 효과를 포함하여 단일 Style 객체로 모든 컨트롤에 대한 완전한 시각적 스타일을 정의할 수 있습니다. StyleKit은 기본 템플릿 구현을 자동으로 처리하므로, 사용자는 색상, 크기, 테두리, 그림자 등 순수하게 시각적인 측면에만 집중할 수 있습니다.
Qt Labs StyleKit 모듈은 Qt 6.11의 기술 미리보기(Technology Preview) 모듈입니다.
© 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.