How to style a QML scroll bar with an image provider
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine. Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean. |
En Ar Bg De El Es Fa Fi Fr Hi Hu It Ja Kn Ko Ms Nl Pl Pt Ru Sq Th Tr Uk Zh
This is not a recommended way to style QML elements, but it does provide an example of creating a QML plugin and creating an image provider. In this example, some parameters have been tailored for Windows XP.
main.qml
This is a simple UI to have something which needs a scroll bar. The ScrollBar element is in the ScrollBar.qml below. It is connected to a ListView element by setting the target property to the id of the list view. The list view is filled with 100 items to give it something to scroll.
import Qt 4.7
import style 1.0
Item {
width: 300
height: 300
ListView {
id: myList
anchors.fill: parent
model: 100
delegate: Text {
text: "item " + index
}
}
ScrollBar {
target: myList
}
}
ScrollBar.qml
This ScrollBar is originally by Gregory Schlomoff. It was modified from the original by changing the source property for Image and BorderImage elements from a image file reference to an image provider reference of the form "image://style/control/subControl", where control and subControl are replaced with names of those QStyle parts. What values those can be are defined in the StyleImageProvider.cpp below. In this example, the only valid values are scrollBar and the subControls of a scroll bar.
/*
ScrollBar component for QML Flickable
Copyright © 2010 Gregory Schlomoff - gregory.schlomoff at gmail.com
This code is released under the MIT license
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
With modifications:
Copyright © 2010 Bradley Smith <bradley at baysmith.com>
Original: http://bitbucket.org/gregschlom/qmlscrollbar/src/tip/ScrollBar.qml
*/
/'''
Usage:
Flickable {
id: myFlickable
…
}
ScrollBar {
target: myFlickable
}
*/
import Qt 4.7
import style 1.0
Item {
property variant target
width: upArrow.width
anchors.top: target.top
anchors.bottom: target.bottom
anchors.margins: 1
anchors.rightMargin: 2
anchors.bottomMargin: 2
anchors.right: target.right
visible: (track.height == slider.height) ? false : true
Image {
id: groove
width: parent.width
anchors.top: parent.top
anchors.bottom: parent.bottom
source: "image://style/scrollBar/addPage"
}
Item {
anchors.fill: parent
Image {
id: upArrow
source: "image://style/scrollBar/subLine"
z: 1
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
onPressed: {
timer.scrollAmount = -10
timer.running = true;
}
onReleased: {
timer.running = false;
}
}
}
Timer {
property int scrollAmount
id: timer
repeat: true
interval: 20
onTriggered: {
target.contentY = Math.max(0, Math.min(target.contentY + scrollAmount,
target.contentHeight- target.height));
}
}
Item {
id: track
anchors.top: upArrow.bottom
anchors.topMargin: 1
anchors.bottom: downArrow.top
width: parent.width
MouseArea {
anchors.fill: parent
onPressed: {
timer.scrollAmount = target.height''' (mouseY < slider.y ? -1 : 1)
timer.running = true;
}
onReleased: {
timer.running = false;
}
}
BorderImage {
id:slider
source: "image://style/scrollBar/slider"
border.left: 3
border.top: 3
border.right: 3
border.bottom: 3
horizontalTileMode: BorderImage.Round
verticalTileMode: BorderImage.Round
width: parent.width
Image {
anchors.centerIn: parent
source: "image://style/scrollBar/sliderDecor"
}
height: Math.min(target.height / target.contentHeight * track.height, track.height)
y: target.visibleArea.yPosition * track.height
MouseArea {
anchors.fill: parent
drag.target: parent
drag.axis: Drag.YAxis
drag.minimumY: 0
drag.maximumY: track.height- height
onPositionChanged: {
if (pressedButtons == Qt.LeftButton) {
target.contentY = slider.y * target.contentHeight / track.height
}
}
}
}
}
Image {
id: downArrow
source: "image://style/scrollBar/addLine"
width: parent.width
z: 1
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
onPressed: {
timer.scrollAmount = 10
timer.running = true;
}
onReleased: {
timer.running = false;
}
}
}
}
}
qmldir
This defines the plugin name and resources for it.
plugin style
ScrollBar 1.0 ScrollBar.qml
StylePlugin.h
#ifndef STYLE_PLUGIN_H
#define STYLE_PLUGIN_H
#include <QDeclarativeExtensionPlugin>
class StylePlugin : public QDeclarativeExtensionPlugin
{
Q_OBJECT
public:
void registerTypes(const char *uri);
void initializeEngine(QDeclarativeEngine *engine, const char *uri);
};
#endif // STYLE_PLUGIN_H
StylePlugin.cpp
#include "StylePlugin.h"
#include "StyleImageProvider.h"
#include <qdeclarative.h>
#include <QDeclarativeEngine>
void StylePlugin::registerTypes(const char *uri)
{
}
void StylePlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri)
{
Q_UNUSED(uri);
engine->addImageProvider("style", new StyleImageProvider);
}
Q_EXPORT_PLUGIN2(style, StylePlugin)
StyleImageProvider.h
The StyleImageProvider class parses the requested pixmap's id for the control and subControl (and an optional state, hover, pressed, etc. which is not used in this example). A QStyleOptionComplex is created and the QStyle from the application is used to paint into a pixmap. The pixmap is cropped to an appropriate size and returned.
#ifndef STYLEIMAGEPROVIDER_H
#define STYLEIMAGEPROVIDER_H
#include <QDeclarativeEngine>
#include <QDeclarativeImageProvider>
class StyleImageProvider : public QDeclarativeImageProvider
{
public:
StyleImageProvider();
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
};
#endif // STYLEIMAGEPROVIDER_H
StyleImageProvider.cpp
#include "StyleImageProvider.h"
#include <QApplication>
#include <QPainter>
#include <QStyleOptionSlider>
namespace
{
QMap<QString, QStyle::ComplexControl> complexControlMap;
QMap<QString, QStyle::SubControl> subControlMap;
}
StyleImageProvider::StyleImageProvider()
: QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap)
{
complexControlMap["scrollBar"] = QStyle::CC_ScrollBar;
subControlMap["none"] = QStyle::SC_None;
subControlMap["addLine"] = QStyle::SC_ScrollBarAddLine;
subControlMap["subLine"] = QStyle::SC_ScrollBarSubLine;
subControlMap["addPage"] = QStyle::SC_ScrollBarAddPage;
subControlMap["subPage"] = QStyle::SC_ScrollBarSubPage;
subControlMap["first"] = QStyle::SC_ScrollBarFirst;
subControlMap["last"] = QStyle::SC_ScrollBarLast;
subControlMap["slider"] = QStyle::SC_ScrollBarSlider;
subControlMap["sliderDecor"] = QStyle::SC_ScrollBarSlider;
subControlMap["groove"] = QStyle::SC_ScrollBarGroove;
}
QPixmap StyleImageProvider::requestPixmap(const QString &id, QSize '''size, const QSize &requestedSize)
{
// Parse the request into complex and sub control parts
QStyle::ComplexControl complexControl = complexControlMap[id.section('/', 0, 0)];
QString subControlName = id.section('/', 1, 1);
QStyle::SubControl subControl = subControlMap[subControlName];
QString state = id.section('/', 2, 2);
// Manually tailored parameters for Windows XP
int width = 16;
int height = 50;
// Setup the style options
QStyleOptionComplex''' option = 0;
if (complexControl QStyle::CC_ScrollBar)
{
QStyleOptionSlider *sliderOption = new QStyleOptionSlider;
option = sliderOption;
if (subControlName "sliderDecor")
// Manually tailored parameter for Windows XP
height = 72;
sliderOption->orientation = Qt::Vertical;
sliderOption->state = QStyle::State_Enabled;
if (state "hover")
sliderOption->state |= QStyle::State_MouseOver;
else if (state "pressed")
sliderOption->state |= QStyle::State_Sunken;
else if (state == "disabled")
sliderOption->state ^= QStyle::State_Enabled;
sliderOption->minimum = 1;
sliderOption->maximum = 100;
sliderOption->sliderPosition = 50;
sliderOption->sliderValue = 50;
sliderOption->singleStep = 1;
sliderOption->pageStep = 100;
}
if (!option)
// Unsupported control
return QPixmap();
option->subControls = subControl;
option->activeSubControls = subControl;
// Create a pixmap of the correct size
QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : width,
requestedSize.height() > 0 ? requestedSize.height() : height);
option->rect = QRect(QPoint(), pixmap.size());
delete option;
// Paint the control
QPainter painter(&pixmap);
QRect subControlRect = qApp->style()->subControlRect(complexControl, option, subControl);
qApp->style()->drawComplexControl(complexControl, option, &painter);
painter.end();
// Copy just the sub control from the painted image
QPixmap sliderPixmap;
if (subControlName == "sliderDecor")
sliderPixmap = pixmap.copy(subControlRect.adjusted(3, 3, –3, –3));
else
sliderPixmap = pixmap.copy(subControlRect);
// Return the size of the pixmap created
if (size)
*size = sliderPixmap.size();
return sliderPixmap;
}
style.pro
TEMPLATE = lib
TARGET = style
QT ''= declarative
CONFIG''= qt plugin
DESTDIR = style
TARGET = $$qtLibraryTarget($$TARGET)
SOURCES ''= StylePlugin.cpp StyleImageProvider.cpp
HEADERS''= StylePlugin.h StyleImageProvider.h
OTHER_FILES = qmldir test.qml ScrollBar.qml main.qml
copy_qmldir.target = $$OUT_PWD/$$DESTDIR/qmldir
copy_qmldir.depends = $$PWD/qmldir
copy_qmldir.commands = $(COPY_FILE) quot;$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)quot; quot;$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)quot;
copy_ScrollBar_qml.target = $$OUT_PWD/$$DESTDIR/ScrollBar.qml
copy_ScrollBar_qml.depends = $$PWD/ScrollBar.qml
copy_ScrollBar_qml.commands = $(COPY_FILE) quot;$$replace(copy_ScrollBar_qml.depends, /, $$QMAKE_DIR_SEP)quot; quot;$$replace(copy_ScrollBar_qml.target, /, $$QMAKE_DIR_SEP)quot;
QMAKE_EXTRA_TARGETS ''= copy_qmldir copy_ScrollBar_qml
PRE_TARGETDEPS''= $$copy_qmldir.target $$copy_ScrollBar_qml.target