c++ - 在代码中使用 Style 自定义 Qt slider 时, handle 偏离凹槽

标签 c++ qt

most examples ,自定义 Qt slider 是这样完成的(使用样式表):

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

这对我来说也很好用。

我有一种情况需要使用动态创建的像素图以编程方式设置背景。使用下面的代码,这就是我完成它的方式。 问题是当我在 Fedora Linux 上时,这个 slider 工作正常。当我在 OSX 或 Windows 上运行时, slider handle 会偏离轨道。

这是它在 OSX 上的样子。注意 Handlebars 是如何脱离凹槽的。左侧是使用样式表自定义的,右侧是使用下面的 Style 对象自定义的。

Style sheet customization vs customization with a Style object

创建 slider 并指定样式:

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

自定义 slider 样式代码:

标题

#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

实现*

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

更新 这个项目的代码是open source and available here

最佳答案

调用 QCommonStyle::subControlRect 并调整宽度/高度是不够的。您还必须重新计算 x/y 位置。

因此您可以使用 QCommonStyle::subControlRect用作计算合适矩形的引用:

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

关于c++ - 在代码中使用 Style 自定义 Qt slider 时, handle 偏离凹槽,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45329036/

相关文章:

c++ - 编译 OGRE 教程示例时出现问题。

c++ - 如何限制类在声明它的 namespace 之外的可见性?

c++ - boost::asio -- asio_handler_deallocate 在 io_service::~io_service() 中调用,在 io_service::stop() 之后

c++ - QSerialPort 和虚拟端口模拟器

c++ - Windows 上 Qt 中的无边框窗口支持 native 功能 : aero snap, DWM 调整大小和最小化

Qt:使用 Modkey(Shift、CTRL 等)检测双击

c++ - 激活上下文导致动态加载的 DLL 上的文件句柄泄漏

C++ 基于上下文的类实现

c++ - 不同类中的 Qt 信号和槽

qt - CMake 与 qmake 的优缺点是什么?