When setting up a Qt slider with a style in the code, the handle leaves the groove

In most examples, the Qt slider is configured as follows (with style):

mySlider = new QSlider(centralWidget); mySlider->setObjectName(QStringLiteral("mySlider")); mySlider->setGeometry(QRect(645, 678, 110, 21)); mySlider->setOrientation(Qt::Horizontal); mySlider->setStyleSheet("QSlider::groove:horizontal {background-image:url(:/main/graphics/mySliderBackround.png);}" "QSlider::handle:horizontal {background-image:url(:/main/graphics/mySliderHandle.png); height:21px; width: 21px;}"); 

This works great for me as well.

I have a situation where I need to programmatically set the background using the created image diagram. Using the code below, I did this. The problem is that when I am on Fedora Linux, this slider works fine. When I am on OSX or Windows, the slider handle turns off.

Here's what it looks like on OSX. Pay attention to how the handle is located behind the groove. The left side is configured using the stylesheet, and the Style object below is configured on the right.

Customizing a stylesheet and customizing with a Style object

Create a slider and style:

 mySlider = new QSlider(centralWidget); mySlider->setObjectName(QStringLiteral("mySlider")); mySlider->setGeometry(QRect(645, 678, 110, 21)); mySlider->setOrientation(Qt::Horizontal); mySlider->setStyle(new MySliderStyle(mySlider->style())); 

Custom slider style code:

Headline

 #ifndef MYSTYLE_H #define MYSTYLE_H #include <QObject> #include <QWidget> #include <QProxyStyle> #include <QPainter> #include <QStyleOption> #include <QtWidgets/QCommonStyle> class MySliderStyle : public QProxyStyle { private: QPixmap groovePixmap; QPixmap handlePixmap; public: LightingSliderStyle(QStyle *style) : QProxyStyle(style) { setColor(QColor::fromRgba(0)); this->handlePixmap = <snip initialize the pixmap>; this->grooveMaskPixmap = <snip initialize the pixmap>; } void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const; QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget) const; void setColor(QColor color); }; #endif // MYSTYLE_H 

Implementation *

 #include "MySliderStyle.h" QRect MySliderStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const { QRect rect; rect = QCommonStyle::subControlRect(control, option, subControl, widget); if (control == CC_Slider && subControl == SC_SliderHandle) { // this is the exact pixel dimensions of the handle png files rect.setWidth(21); rect.setHeight(21); } else if (control == CC_Slider && subControl == SC_SliderGroove) { // this is the exact pixel dimensions of the slider png files rect.setWidth(widget->width()); rect.setHeight(widget->height()); } return rect; } void MySliderStyle::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const { if (control == CC_Slider) { if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { QRect groove = subControlRect(CC_Slider, slider, SC_SliderGroove, widget); QRect handle = subControlRect(CC_Slider, slider, SC_SliderHandle, widget); if ((slider->subControls & SC_SliderGroove) && groove.isValid()) { Qt::BGMode oldMode = painter->backgroundMode(); painter->setBackgroundMode(Qt::TransparentMode); painter->drawPixmap(groove, groovePixmap); painter->setBackgroundMode(oldMode); } if ((slider->subControls & SC_SliderHandle) && handle.isValid()) { Qt::BGMode oldMode = painter->backgroundMode(); painter->setBackgroundMode(Qt::TransparentMode); painter->drawPixmap(handle, handlePixmap); painter->setBackgroundMode(oldMode); } } } else { QProxyStyle::drawComplexControl(control, option, painter, widget); } } void MySliderStyle::setColor(QColor color) { QImage myGrooveImage; // <snip> // Code to create the custom pixmap // <snip> groovePixmap = QPixmap::fromImage(myGrooveImage); } 

UPDATE The code for this project is open source and is available here.

+5
source share
1 answer

Calling QCommonStyle :: subControlRect and setting the width / height is not enough. You must also recalculate the x / y position.

You can use the QCommonStyle :: subControlRect function as a link to calculate the correct rectangle:

 QRect LightingSliderStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const { if (control == CC_Slider) { if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { QRect ret; int tickOffset = 0; int thickness = 21; // height int len = 21; // width switch (subControl) { case SC_SliderHandle: { int sliderPos = 0; bool horizontal = slider->orientation == Qt::Horizontal; sliderPos = sliderPositionFromValue(slider->minimum, slider->maximum+1, slider->sliderPosition, (horizontal ? slider->rect.width() : slider->rect.height()) - len, slider->upsideDown); if (horizontal) ret.setRect(slider->rect.x() + sliderPos, slider->rect.y() + tickOffset, len, thickness); else ret.setRect(slider->rect.x() + tickOffset, slider->rect.y() + sliderPos, thickness, len); break; } case SC_SliderGroove: if (slider->orientation == Qt::Horizontal) ret.setRect(slider->rect.x(), slider->rect.y() + tickOffset, slider->rect.width(), thickness); else ret.setRect(slider->rect.x() + tickOffset, slider->rect.y(), thickness, slider->rect.height()); break; default: break; } return visualRect(slider->direction, slider->rect, ret); } } return QCommonStyle::subControlRect(control, option, subControl, widget); } 
+3
source

Source: https://habr.com/ru/post/1270223/


All Articles