Qt QSlider双滑块

目录

说明:这里参考许多大佬资料,但是当时记着赶项目,忘记搜集大佬们链接,非常感谢大佬们无私奉献。

1.继承QWidget

2.继承QSlider(有缺陷,部分功能没有实现,可以研究一下)

3.继承QWidget与1有点异曲同工之处(也是自绘)

4.使用小聪明,但是可以使用Qt样式


说明:这里参考许多大佬资料,但是当时记着赶项目,忘记搜集大佬们链接,非常感谢大佬们无私奉献。

1.继承QWidget

如果项目需求对QSlider要求不高(使用自绘方法,无法使用样式)继承QWidget,里面基本功能都实现了,个别需要自己在研究实现,效果如如下

#pragma once

#include <QWidget>
#include <QPainter>
#include <QMouseEvent>

class RangeSlider : public QWidget
{
    Q_OBJECT
    Q_ENUMS(RangeSliderTypes)

public:
    enum Option {
        NoHandle = 0x0,
        LeftHandle = 0x1,
        RightHandle = 0x2,
        DoubleHandles = LeftHandle | RightHandle
    };
    Q_DECLARE_FLAGS(Options, Option)

    RangeSlider( QWidget* aParent = Q_NULLPTR);
    RangeSlider( Qt::Orientation ori, Options t = DoubleHandles, QWidget* aParent = Q_NULLPTR);

    QSize minimumSizeHint() const override;

    int GetMinimun() const;
    void SetMinimum(int aMinimum);

    int GetMaximun() const;
    void SetMaximum(int aMaximum);

    int GetLowerValue() const;
    void SetLowerValue(int aLowerValue);

    int GetUpperValue() const;
    void SetUpperValue(int aUpperValue);

    void SetRange(int aMinimum, int aMaximum);

protected:
    void paintEvent(QPaintEvent* aEvent) override;
    void mousePressEvent(QMouseEvent* aEvent) override;
    void mouseMoveEvent(QMouseEvent* aEvent) override;
    void mouseReleaseEvent(QMouseEvent* aEvent) override;
    void changeEvent(QEvent* aEvent) override;

    QRectF firstHandleRect() const;
    QRectF secondHandleRect() const;
    QRectF handleRect(int aValue) const;

signals:
    void lowerValueChanged(int aLowerValue);
    void upperValueChanged(int aUpperValue);
    void rangeChanged(int aMin, int aMax);

public slots:
    void setLowerValue(int aLowerValue);
    void setUpperValue(int aUpperValue);
    void setMinimum(int aMinimum);
    void setMaximum(int aMaximum);

private:
    Q_DISABLE_COPY(RangeSlider)
    float currentPercentage();
    int validLength() const;

    int mMinimum;
    int mMaximum;
    int mLowerValue;
    int mUpperValue;
    bool mFirstHandlePressed;
    bool mSecondHandlePressed;
    int mInterval;
    int mDelta;
    QColor mBackgroudColorEnabled;
    QColor mBackgroudColorDisabled;
    QColor mBackgroudColor;
    Qt::Orientation orientation;
    Options type;
};

Q_DECLARE_OPERATORS_FOR_FLAGS(RangeSlider::Options)

#include "RangeSlider.h"
#include <QDebug>

namespace
{

const int scHandleSideLength = 11;
const int scSliderBarHeight = 5;
const int scLeftRightMargin = 1;

}

RangeSlider::RangeSlider(QWidget* aParent)
    : QWidget(aParent),
      mMinimum(0),
      mMaximum(100),
      mLowerValue(0),
      mUpperValue(100),
      mFirstHandlePressed(false),
      mSecondHandlePressed(false),
      mInterval(mMaximum - mMinimum),
      mBackgroudColorEnabled(QColor(0x1E, 0x90, 0xFF)),
      mBackgroudColorDisabled(Qt::darkGray),
      mBackgroudColor(mBackgroudColorEnabled),
      orientation(Qt::Horizontal)
{
    setMouseTracking(true);
}

RangeSlider::RangeSlider(Qt::Orientation ori, Options t, QWidget* aParent)
    : QWidget(aParent),
      mMinimum(0),
      mMaximum(100),
      mLowerValue(0),
      mUpperValue(100),
      mFirstHandlePressed(false),
      mSecondHandlePressed(false),
      mInterval(mMaximum - mMinimum),
      mBackgroudColorEnabled(QColor(0x1E, 0x90, 0xFF)),
      mBackgroudColorDisabled(Qt::darkGray),
      mBackgroudColor(mBackgroudColorEnabled),
      orientation(ori),
      type(t)
{
    setMouseTracking(true);
}

void RangeSlider::paintEvent(QPaintEvent* aEvent)
{

    Q_UNUSED(aEvent);
    QPainter painter(this);

    // Background
    QRectF backgroundRect;
    if(orientation == Qt::Horizontal)
        backgroundRect = QRectF(scLeftRightMargin, (height() - scSliderBarHeight) / 2, width() - scLeftRightMargin * 2, scSliderBarHeight);
    else
        backgroundRect = QRectF((width() - scSliderBarHeight) / 2, scLeftRightMargin, scSliderBarHeight, height() - scLeftRightMargin*2);

    QPen pen(Qt::gray, 0.8);
    painter.setPen(pen);
    painter.setRenderHint(QPainter::Qt4CompatiblePainting);
    QBrush backgroundBrush(QColor(0xD0, 0xD0, 0xD0));
    painter.setBrush(backgroundBrush);
    painter.drawRoundedRect(backgroundRect, 1, 1);

    // First value handle rect
    pen.setColor(Qt::darkGray);
    pen.setWidth(0.5);
    painter.setPen(pen);
    painter.setRenderHint(QPainter::Antialiasing);
    QBrush handleBrush(QColor(0xFA, 0xFA, 0xFA));
    painter.setBrush(handleBrush);
    QRectF leftHandleRect = firstHandleRect();
    if(type.testFlag(LeftHandle))
        painter.drawRoundedRect(leftHandleRect, 2, 2);

    // Second value handle rect
    QRectF rightHandleRect = secondHandleRect();
    if(type.testFlag(RightHandle))
        painter.drawRoundedRect(rightHandleRect, 2, 2);

    // Handles
    painter.setRenderHint(QPainter::Antialiasing, false);
    QRectF selectedRect(backgroundRect);
    if(orientation == Qt::Horizontal) {
        selectedRect.setLeft((type.testFlag(LeftHandle) ? leftHandleRect.right() : leftHandleRect.left()) + 0.5);
        selectedRect.setRight((type.testFlag(RightHandle) ? rightHandleRect.left() : rightHandleRect.right()) - 0.5);
    } else {
        selectedRect.setTop((type.testFlag(LeftHandle) ? leftHandleRect.bottom() : leftHandleRect.top()) + 0.5);
        selectedRect.setBottom((type.testFlag(RightHandle) ? rightHandleRect.top() : rightHandleRect.bottom()) - 0.5);
    }
    QBrush selectedBrush(mBackgroudColor);
    painter.setBrush(selectedBrush);
    painter.drawRect(selectedRect);
}

QRectF RangeSlider::firstHandleRect() const
{
    float percentage = (mLowerValue - mMinimum) * 1.0 / mInterval;
    return handleRect(percentage * validLength() + scLeftRightMargin);
}

QRectF RangeSlider::secondHandleRect() const
{
    float percentage = (mUpperValue - mMinimum) * 1.0 / mInterval;
    return handleRect(percentage * validLength() + scLeftRightMargin + (type.testFlag(LeftHandle) ? scHandleSideLength : 0));
}

QRectF RangeSlider::handleRect(int aValue) const
{
    if(orientation == Qt::Horizontal)
        return QRect(aValue, (height()-scHandleSideLength) / 2, scHandleSideLength, scHandleSideLength);
    else
        return QRect((width()-scHandleSideLength) / 2, aValue, scHandleSideLength, scHandleSideLength);
}

void RangeSlider::mousePressEvent(QMouseEvent* aEvent)
{
    if(aEvent->buttons() & Qt::LeftButton)
    {
        int posCheck, posMax, posValue, firstHandleRectPosValue, secondHandleRectPosValue;
        posCheck = (orientation == Qt::Horizontal) ? aEvent->pos().y() : aEvent->pos().x();
        posMax = (orientation == Qt::Horizontal) ? height() : width();
        posValue = (orientation == Qt::Horizontal) ? aEvent->pos().x() : aEvent->pos().y();
        firstHandleRectPosValue = (orientation == Qt::Horizontal) ? firstHandleRect().x() : firstHandleRect().y();
        secondHandleRectPosValue = (orientation == Qt::Horizontal) ? secondHandleRect().x() : secondHandleRect().y();

        mSecondHandlePressed = secondHandleRect().contains(aEvent->pos());
        mFirstHandlePressed = !mSecondHandlePressed && firstHandleRect().contains(aEvent->pos());
        if(mFirstHandlePressed)
        {
            mDelta = posValue - (firstHandleRectPosValue + scHandleSideLength / 2);
        }
        else if(mSecondHandlePressed)
        {
            mDelta = posValue - (secondHandleRectPosValue + scHandleSideLength / 2);
        }

        if(posCheck >= 2
           && posCheck <= posMax - 2)
        {
            int step = mInterval / 10 < 1 ? 1 : mInterval / 10;
            if(posValue < firstHandleRectPosValue)
                setLowerValue(mLowerValue - step);
            else if(((posValue > firstHandleRectPosValue + scHandleSideLength) || !type.testFlag(LeftHandle))
                    && ((posValue < secondHandleRectPosValue) || !type.testFlag(RightHandle)))
            {
                if(type.testFlag(DoubleHandles))
                    if(posValue - (firstHandleRectPosValue + scHandleSideLength) <
                            (secondHandleRectPosValue - (firstHandleRectPosValue + scHandleSideLength)) / 2)
                        setLowerValue((mLowerValue + step < mUpperValue) ? mLowerValue + step : mUpperValue);
                    else
                        setUpperValue((mUpperValue - step > mLowerValue) ? mUpperValue - step : mLowerValue);
                else if(type.testFlag(LeftHandle))
                    setLowerValue((mLowerValue + step < mUpperValue) ? mLowerValue + step : mUpperValue);
                else if(type.testFlag(RightHandle))
                    setUpperValue((mUpperValue - step > mLowerValue) ? mUpperValue - step : mLowerValue);
            }
            else if(posValue > secondHandleRectPosValue + scHandleSideLength)
                setUpperValue(mUpperValue + step);
        }
    }
}

void RangeSlider::mouseMoveEvent(QMouseEvent* aEvent)
{
    if(aEvent->buttons() & Qt::LeftButton)
    {
        int posValue, firstHandleRectPosValue, secondHandleRectPosValue;
        posValue = (orientation == Qt::Horizontal) ? aEvent->pos().x() : aEvent->pos().y();
        firstHandleRectPosValue = (orientation == Qt::Horizontal) ? firstHandleRect().x() : firstHandleRect().y();
        secondHandleRectPosValue = (orientation == Qt::Horizontal) ? secondHandleRect().x() : secondHandleRect().y();

        if(mFirstHandlePressed && type.testFlag(LeftHandle))
        {
            if(posValue - mDelta + scHandleSideLength / 2 <= secondHandleRectPosValue)
            {
                setLowerValue((posValue - mDelta - scLeftRightMargin - scHandleSideLength / 2) * 1.0 / validLength() * mInterval + mMinimum);
            }
            else
            {
                setLowerValue(mUpperValue);
            }
        }
        else if(mSecondHandlePressed && type.testFlag(RightHandle))
        {
            if(firstHandleRectPosValue + scHandleSideLength * (type.testFlag(DoubleHandles) ? 1.5 : 0.5) <= posValue - mDelta)
            {
                setUpperValue((posValue - mDelta - scLeftRightMargin - scHandleSideLength / 2 - (type.testFlag(DoubleHandles) ? scHandleSideLength : 0)) * 1.0 / validLength() * mInterval + mMinimum);
            }
            else
            {
                setUpperValue(mLowerValue);
            }
        }
    }
}

void RangeSlider::mouseReleaseEvent(QMouseEvent* aEvent)
{
    Q_UNUSED(aEvent);

    mFirstHandlePressed = false;
    mSecondHandlePressed = false;
}

void RangeSlider::changeEvent(QEvent* aEvent)
{
    if(aEvent->type() == QEvent::EnabledChange)
    {
        if(isEnabled())
        {
            mBackgroudColor = mBackgroudColorEnabled;
        }
        else
        {
            mBackgroudColor = mBackgroudColorDisabled;
        }
        update();
    }
}

QSize RangeSlider::minimumSizeHint() const
{
    return QSize(scHandleSideLength * 2 + scLeftRightMargin * 2, scHandleSideLength);
}

int RangeSlider::GetMinimun() const
{
    return mMinimum;
}

void RangeSlider::SetMinimum(int aMinimum)
{
    setMinimum(aMinimum);
}

int RangeSlider::GetMaximun() const
{
    return mMaximum;
}

void RangeSlider::SetMaximum(int aMaximum)
{
    setMaximum(aMaximum);
}

int RangeSlider::GetLowerValue() const
{
    return mLowerValue;
}

void RangeSlider::SetLowerValue(int aLowerValue)
{
    setLowerValue(aLowerValue);
}

int RangeSlider::GetUpperValue() const
{
    return mUpperValue;
}

void RangeSlider::SetUpperValue(int aUpperValue)
{
    setUpperValue(aUpperValue);
}

void RangeSlider::setLowerValue(int aLowerValue)
{
    if(aLowerValue > mMaximum)
    {
        aLowerValue = mMaximum;
    }

    if(aLowerValue < mMinimum)
    {
        aLowerValue = mMinimum;
    }

    mLowerValue = aLowerValue;
    emit lowerValueChanged(mLowerValue);

    update();
}

void RangeSlider::setUpperValue(int aUpperValue)
{
    if(aUpperValue > mMaximum)
    {
        aUpperValue = mMaximum;
    }

    if(aUpperValue < mMinimum)
    {
        aUpperValue = mMinimum;
    }

    mUpperValue = aUpperValue;
    emit upperValueChanged(mUpperValue);

    update();
}

void RangeSlider::setMinimum(int aMinimum)
{
    if(aMinimum <= mMaximum)
    {
        mMinimum = aMinimum;
    }
    else
    {
        int oldMax = mMaximum;
        mMinimum = oldMax;
        mMaximum = aMinimum;
    }
    mInterval = mMaximum - mMinimum;
    update();

    setLowerValue(mMinimum);
    setUpperValue(mMaximum);

    emit rangeChanged(mMinimum, mMaximum);
}

void RangeSlider::setMaximum(int aMaximum)
{
    if(aMaximum >= mMinimum)
    {
        mMaximum = aMaximum;
    }
    else
    {
        int oldMin = mMinimum;
        mMaximum = oldMin;
        mMinimum = aMaximum;
    }
    mInterval = mMaximum - mMinimum;
    update();

    setLowerValue(mMinimum);
    setUpperValue(mMaximum);

    emit rangeChanged(mMinimum, mMaximum);
}

int RangeSlider::validLength() const
{
    int len = (orientation == Qt::Horizontal) ? width() : height();
    return len - scLeftRightMargin * 2 - scHandleSideLength * (type.testFlag(DoubleHandles) ? 2 : 1);
}

void RangeSlider::SetRange(int aMinimum, int mMaximum)
{
    setMinimum(aMinimum);
    setMaximum(mMaximum);
}

//调用方法 这里只写代码段 .h
QHBoxLayout *layout;
RangeSlider *rsH, *rsV, *rsHsingleLeft, *rsVsingleLeft, *rsHsingleRight, *rsVsingleRight;

//.cpp
rsH = new RangeSlider(Qt::Horizontal, RangeSlider::Option::DoubleHandles, nullptr);
    rsV = new RangeSlider(Qt::Vertical, RangeSlider::Option::DoubleHandles, nullptr);
    rsHsingleLeft = new RangeSlider(Qt::Horizontal, RangeSlider::Option::LeftHandle, nullptr);
    rsVsingleLeft = new RangeSlider(Qt::Vertical, RangeSlider::Option::LeftHandle, nullptr);
    rsHsingleRight = new RangeSlider(Qt::Horizontal, RangeSlider::Option::RightHandle, nullptr);
    rsVsingleRight = new RangeSlider(Qt::Vertical, RangeSlider::Option::RightHandle, nullptr);
layout = new QHBoxLayout();
layout->addWidget(rsH);
layout->addWidget(rsV);
layout->addWidget(rsHsingleLeft);
layout->addWidget(rsVsingleLeft);
layout->addWidget(rsHsingleRight);
layout->addWidget(rsVsingleRight);
widget->setLayout(layout);
setCentralWidget(widget);
resize(QDesktopWidget().availableGeometry(this).size() * 0.7);

2.继承QSlider(有缺陷,部分功能没有实现,可以研究一下)

 该方法使用QPixmap贴图方式,然后将贴图在滑条范围内移动,下面分别是.h和cpp

#ifndef SUPERSLIDER_H
#define SUPERSLIDER_H

#pragma once

#include "qslider.h"
#include "qlabel.h"


/*
*  Super sick nasty awesome double handled slider!
*
*   @author Steve
*/
class SuperSliderHandle;

class SuperSlider: public QSlider
{
  Q_OBJECT
public:
  SuperSlider(QWidget *parent = 0);
  SuperSliderHandle *alt_handle;
  void mouseReleaseEvent(QMouseEvent *event);
  int alt_value();
  void alt_setValue(int value);
  void Reset();
  void alt_update();
signals:
  void alt_valueChanged(int);
};

class SuperEventFilter : public QObject
{
public:
  SuperEventFilter(SuperSlider *_grandParent)
  {grandParent = _grandParent;};

protected:
  bool eventFilter(QObject* obj, QEvent* event);

private:
  SuperSlider *grandParent;
};

class SuperSliderHandle: public QLabel
{
  Q_OBJECT
public:
    SuperSliderHandle(SuperSlider *parent = 0);
    void mousePressEvent(QMouseEvent *event);
    int value();
    int mapValue();
    SuperSlider *parent;
    bool handleActivated;
private:
  SuperEventFilter *filter;
  public slots:
    void setValue(double value);
};

#endif // SUPERSLIDER_H
#include "SuperSlider.h"
//Qt
#include <QMouseEvent>
#include "qmimedata.h"
#include "qdrag.h"
#include "qwidgetaction.h"
#include "qapplication.h"
#include "qpixmap.h"
#include "qcursor.h"
#include "qguiapplication.h"
#include "qdir.h"
#include <QProxyStyle>

class SliderProxy : public QProxyStyle
{
public:
  int pixelMetric ( PixelMetric metric, const QStyleOption * option = 0, const QWidget * widget = 0 ) const
  {
    switch(metric) {
    case PM_SliderThickness  : return 25;
    case PM_SliderLength     : return 25;
    default                  : return (QProxyStyle::pixelMetric(metric,option,widget));
    }
  }
};

SuperSlider::SuperSlider(QWidget *parent)
  : QSlider(parent)
{
  //styling
  setOrientation(Qt::Horizontal);
  setAcceptDrops(true);
  SliderProxy *aSliderProxy = new SliderProxy();

  //hard coded path to image :/ sorry
  QString path = "d:/1.png";// QDir::fromNativeSeparators(ImagesPath("handle.png"));
  setStyleSheet("QSlider::handle { image: url(" + path + "); }");
  setStyle(aSliderProxy);

  //setting up the alternate handle
  alt_handle = new SuperSliderHandle(this);
  addAction(new QWidgetAction(alt_handle));
  alt_handle->move(this->pos().x() + this->width()- alt_handle->width(), this->pos().y() );

}

SuperSliderHandle::SuperSliderHandle(SuperSlider *_parent)
  : QLabel(_parent)
{
  parent = _parent;
  filter = new SuperEventFilter(parent);

  //styling
  setAcceptDrops(true);
  //hard coded path to image :/ sorry
  QPixmap pix = QPixmap("d:/2.png");//QPixmap(ImagesPath("handle.png"));
  pix =  pix.scaled(25, 25, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
  setPixmap(pix);
}

int SuperSlider::alt_value()
{
  return alt_handle->value();
}

void SuperSlider::alt_setValue(int value)
{
  alt_handle->setValue(value);
}

void SuperSlider::mouseReleaseEvent(QMouseEvent *mouseEvent)
{
  if (mouseEvent->button() == Qt::LeftButton)
  {
    alt_handle->show();
    alt_handle->handleActivated = false;
  }
  mouseEvent->accept();
}

void SuperSlider::alt_update()
{
  QPoint posCursor(QCursor::pos());
  QPoint posParent(mapToParent(mapToGlobal(pos())));
  QPoint point(alt_handle->mapToParent(alt_handle->mapFromGlobal(QCursor::pos())).x(),alt_handle->y());
  int horBuffer = (alt_handle->width());
  bool lessThanMax = mapToParent(point).x() < pos().x()+ width() - horBuffer;
  bool greaterThanMin = mapToParent(point).x() > pos().x();
  if(lessThanMax && greaterThanMin)
    alt_handle->move(point);
  emit alt_valueChanged(alt_value());
}

void SuperSliderHandle::mousePressEvent(QMouseEvent *mouseEvent)
{
  qGuiApp->installEventFilter(filter);
  parent->clearFocus();
}

bool SuperEventFilter::eventFilter(QObject* obj, QEvent* event)
{
  switch(event->type())
  {
  case QEvent::MouseButtonRelease:
    qGuiApp->removeEventFilter(this);
    return true;
    break;
  case QEvent::MouseMove:
    grandParent->alt_update();
    return true;
    break;
  default:
    return QObject::eventFilter(obj, event);
  }
  return false;
}

void SuperSliderHandle::setValue(double value)
{
  double width = parent->width(), position = pos().x();
  double range = parent->maximum() - parent->minimum();
  int location = (value - parent->minimum())/range;
  location = location *width;
  move(y(),location);
}

int SuperSliderHandle::value()
{
  double width = parent->width(), position = pos().x();
  double value = position/width;
  double range = parent->maximum() - parent->minimum();
  return parent->minimum() + (value * range);
}
void SuperSlider::Reset()
{
  int horBuffer = (alt_handle->width());
  QPoint myPos = mapToGlobal(pos());
  QPoint point(myPos.x() + width() - horBuffer, myPos.y()- alt_handle->height());
  point = alt_handle->mapFromParent(point);

  alt_handle->move(point);
  alt_handle->show();
  alt_handle->raise();

}

3.继承QWidget与1有点异曲同工之处(也是自绘)

#pragma once

#include <QWidget>
#include <QWidget>
#include <QPainter>
#include <QMouseEvent>
#include <QFontMetrics> 
#include "ui_CNW24GDoubleSlider.h"

class DoubleSlider;

class CNW24GDoubleSlider : public QWidget
{
	Q_OBJECT

public:
	CNW24GDoubleSlider(QWidget *parent = nullptr);
	~CNW24GDoubleSlider();

private:
	DoubleSlider* m_pDoubleSlider = nullptr;
private:
	Ui::CNW24GDoubleSliderClass ui;
};


class DoubleSlider : public QWidget
{
	Q_OBJECT
public:
	DoubleSlider(QWidget* parent = 0);
	void setRange(float min, float max);
	void setSingleStep(float step);

	enum State { MinHandle, MaxHandle, None };

	float minValue() const;
	float maxValue() const;

	float minRange() const;
	float maxRange() const;

	void SetPressValue(float fpos);
	void SetValue(int npos);

public slots:
	void setLabel(const QString& label);
	void setMaxValue(float val);
	void setMinValue(float val);

signals:
	void minValueChanged(float);
	void maxValueChanged(float);

private:
	float m_min;
	float m_max;
	float m_singleStep;

	float m_minValue;
	float m_maxValue;

	QRect minHandleRegion;
	QRect maxHandleRegion;

	State m_state;

	QString m_label;

protected:
	void paintEvent(QPaintEvent* event);
	void paintColoredRect(QRect rect, QColor color, QPainter* painter);
	void paintValueLabel(QPainter* painter);

	void mousePressEvent(QMouseEvent* event);
	void mouseMoveEvent(QMouseEvent* event);

	void keyPressEvent(QKeyEvent* event);
	void leaveEvent(QEvent* event);

};
#include "CNW24GDoubleSlider.h"

CNW24GDoubleSlider::CNW24GDoubleSlider(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);
	ui.nameLabel->setText(u8"亮度");
	ui.nameLabel->setStyleSheet("width: 54px;height: 20px;color: #FFFFFF; background-color:none;");
	m_pDoubleSlider = new DoubleSlider(this);
	m_pDoubleSlider->move(30, 50);
}

CNW24GDoubleSlider::~CNW24GDoubleSlider()
{
}

/// <summary>
/// DoubleSlider
/// </summary>
/// <param name="parent"></param>
DoubleSlider::DoubleSlider(QWidget* parent)
	: QWidget(parent)
	, m_min(0.0f)
	, m_max(100.0f)
	, m_singleStep(0.1f)
	, m_minValue(0.0f)
	, m_maxValue(100.0f)
	, m_state(None)
{
	setFixedWidth(200);
	setFixedHeight(550);
	setFocusPolicy(Qt::StrongFocus);

}

void DoubleSlider::paintEvent(QPaintEvent* event)
{
	QWidget::paintEvent(event);
	QPainter painter(this);
	paintValueLabel(&painter);
}

void DoubleSlider::paintColoredRect(QRect rect, QColor color, QPainter* painter)
{
	painter->fillRect(rect, QBrush(color));
}

void DoubleSlider::paintValueLabel(QPainter* painter)
{
	// painter->setBrush(Qt::NoBrush);
	painter->setBrush(Qt::NoBrush);
	painter->setPen(Qt::white);
	painter->setFont(QFont("Arial", 12));

	QString minValueString = QString::number(m_minValue, 'f', 0);
	QString maxValueString = QString::number(m_maxValue, 'f', 0);

	QFontMetrics metrics = painter->fontMetrics();
	int mintextWidth = metrics.width(minValueString);
	int maxtextWidth = metrics.width(maxValueString);
	int textHeight = metrics.height();

	//---- paint text
	painter->drawText(QRectF(2, 4, mintextWidth, textHeight), minValueString);
	painter->drawText(QRectF(width() - maxtextWidth - 2, 4, maxtextWidth, textHeight), maxValueString);


	//----- paint label text
	painter->setFont(QFont("Arial", 12));
	metrics = painter->fontMetrics();
	int labelWidth = metrics.width(m_label);
	int labelHeight = metrics.height();
	QRectF textRect = QRectF((width() / 2 - labelWidth / 2), 0, labelWidth, labelHeight);
	painter->drawText(textRect, m_label);
	// end


	int minPos = (m_minValue - m_min) * width() / (m_max - m_min);
	int maxPos = (m_maxValue - m_min) * width() / (m_max - m_min);

	if (minPos <= 4) {
		minPos = 4;
	}
	else if (minPos >= width() - 8) {
		minPos = width() - 8;
	}
	else {}

	if (maxPos <= 4) {
		maxPos = 4;
	}
	else if (maxPos >= width() - 8) {
		maxPos = width() - 8;
	}
	else {}


	//----- paint groove

	//滑块槽
	paintColoredRect(QRect(4, 37, width() - 8, 2), Qt::yellow, painter);
	//滑块内槽
	paintColoredRect(QRect(minPos + 4, 37, maxPos - minPos, 2), QColor(51, 153, 155), painter);

	//----- handle

	minHandleRegion = QRect(minPos, 30, 8, 16);
	maxHandleRegion = QRect(maxPos, 30, 8, 16);

	//-----paint Handle
	QColor minColor = (m_state == MinHandle) ? QColor(51, 153, 155) : Qt::darkGray;
	QColor maxColor = (m_state == MaxHandle) ? QColor(51, 153, 155) : Qt::darkGray;
	paintColoredRect(minHandleRegion, minColor, painter); //左侧滑块
	paintColoredRect(maxHandleRegion, maxColor, painter); //右侧滑块
}

inline float getValidValue(float val, float min, float max)
{
	float tmp = std::max(val, min);
	return std::min(tmp, max);
}


void DoubleSlider::setRange(float min, float max)
{
	m_min = min;
	m_max = max;

	if (minValue() < m_min)
		setMinValue(m_min);

	if (maxValue() > m_max) {
		setMaxValue(m_max);
	}
}

void DoubleSlider::setSingleStep(float step)
{
	m_singleStep = step;
}

float DoubleSlider::minValue() const
{
	return m_minValue;
}
void DoubleSlider::setMinValue(float val)
{
	if (fabs(m_minValue - val) > 0.0001) {
		m_minValue = val;
		//emit minValueChanged(val);
	}
}

float DoubleSlider::maxValue() const
{
	return m_maxValue;
}
void DoubleSlider::setMaxValue(float val)
{
	if (fabs(m_maxValue - val) > 0.0001) {
		m_maxValue = val;
		//emit maxValueChanged(val);
	}
}

void DoubleSlider::setLabel(const QString& label)
{
	m_label = label;
	update();
}

void DoubleSlider::leaveEvent(QEvent* event)
{
	QWidget::leaveEvent(event);
	m_state = None;
	update();
}

float DoubleSlider::minRange() const
{
	return m_min;
}
float DoubleSlider::maxRange() const
{
	return m_max;
}




void DoubleSlider::mousePressEvent(QMouseEvent* event)
{
	if (minHandleRegion.contains(event->pos())) {
		m_state = MinHandle;
	}
	else if (maxHandleRegion.contains(event->pos())) {
		m_state = MaxHandle;
	}
	else {
		SetPressValue(event->x());
		m_state = None;
	}

	if (fabs(minValue() - maxValue()) < 0.001) {
		if (fabs(minValue() - m_min) < 0.001) {
			m_state = MaxHandle;
		}
		else if (fabs(minValue() - m_max) < 0.001) {
			m_state = MinHandle;
		}
		else {}
	}

	update();
}
void DoubleSlider::SetPressValue(float fpos)
{
	float move = fpos * (m_max - m_min) * 1.0 / width() + m_min;
	abs(m_minValue - move) > abs(m_maxValue - move) ? m_state = MaxHandle : m_state = MinHandle;
	if (MaxHandle == m_state)
	{
		float val = getValidValue(move, minValue(), m_max);
		setMaxValue(val);
	}
	else
	{
		float val = getValidValue(move, m_min, maxValue());
		setMinValue(val);
	}

}

void DoubleSlider::SetValue(int npos)
{
	float val = getValidValue(npos, m_min, maxValue());
	setMinValue(val);
}

void DoubleSlider::mouseMoveEvent(QMouseEvent* event)
{
	if (event->buttons() & Qt::LeftButton) {
		float move = event->x() * (m_max - m_min) * 1.0 / width() + m_min;

		switch (m_state) {
		case MinHandle: {
			float val = getValidValue(move, m_min, maxValue());
			setMinValue(val);
			break;
		}

		case MaxHandle: {
			float val = getValidValue(move, minValue(), m_max);
			setMaxValue(val);
			break;
		}
		case None:default: break;
		}
	}
	update();
}


void DoubleSlider::keyPressEvent(QKeyEvent* event)
{
	QWidget::keyPressEvent(event);

	if (event->key() == Qt::Key_Left) {
		if (m_state == MinHandle) {
			float val = getValidValue(minValue() - m_singleStep, m_min, maxValue());
			setMinValue(val);
		}
		else if (m_state == MaxHandle) {
			float val = getValidValue(maxValue() - m_singleStep, minValue(), m_max);
			setMaxValue(val);
		}
		else {}
	}
	else if (event->key() == Qt::Key_Right) {
		if (m_state == MinHandle) {
			float val = getValidValue(minValue() + m_singleStep, m_min, maxValue());
			setMinValue(val);
		}
		else if (m_state == MaxHandle) {
			float val = getValidValue(maxValue() + m_singleStep, minValue(), m_max);
			setMaxValue(val);
		}
		else {}
	}

	update();

}

4.使用小聪明,但是可以使用Qt样式

如果你之前想到使用QSlide重叠在一起,那么聪明的你怎么处理QSlider点击响应冲突和覆盖问题呢?

没错,这种情况只能使用样式和重写处理消息事件过滤。首先,处理覆盖问题,若有有什么办法能够让最上层滑轨透明,显示下层样式,直接来代码吧,这里需要注意是前后问题,如果你想QSlider1在最上层那么只能隐藏滑轨和背景,QSlider2在最下层,反之亦然。

ui.controlSlider->raise();//显示在最上层
//ui.controlSlider_2->lower();//显示在最下层
ui.controlSlider_2->setStyleSheet("QSlider::groove:horizontal{background:transparent;width:258px;height:16px;border-radius: 5px;border-image: url(:/res/Brightness_Default2x.png);background-repeat:none;}"//
			"QSlider::handle:horizontal{border-radius: 20px;width:15px;height: 30px;margin-top: -8px;margin-bottom: -8px;border-image: url(:/res/effect_default2x.png);background-repeat:none;}"//滑动条上滑块
			"QSlider{border: 24px solid transparent;border-left: 2px;border-right: 2px;border-radius: 15px;}");
ui.controlSlider->setStyleSheet("QSlider::groove:horizontal{background:transparent;width:258px;height:16px;border-radius: 5px;border:transparent;background-repeat:none;}"//
			"QSlider::handle:horizontal{border-radius: 20px;width:15px;height: 30px;margin-top: -8px;margin-bottom: -8px;border-image: url(:/res/effect_default2x.png);background-repeat:none;}"//滑动条上滑块
			"QSlider{border: 24px solid transparent;border-left: 2px;border-right: 2px;border-radius: 15px;}");
ui.controlSlider->installEventFilter(this);
ui.controlSlider_2->installEventFilter(this);

那么就剩下消息过滤,如果是QSlider1的消息,就要屏蔽QSlider2的消息响应(并不是完全屏蔽,而是根据距离去响应),关于鼠标点击距离你可以用这个方法计算,根据距离哪个近就让那个控件在最上方,记得修改样式

QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
// 如果是QSlider1的就填1的ui就可以了
int value = QStyle::sliderValueFromPosition(ui.controlSlider_2->minimum(), ui.controlSlider_2->maximum(), mouseEvent->pos().x(), ui.controlSlider_2->width());

1.需要注意QEvent::MouseMove 移动滑轨时候,有可能会出现QSlist1<QSlider2(也就是划超位置),再次去点击(如果代码里位置限制)发现会有问题,这里需要滑动完最后判断QSlider2的当前位置,如果超了要特殊处理

2.第二个问题是,当我们QSlider双滑轨切换前后位置会出现,最后的滑块没动,动的是最前面的,这是因为我们鼠标一直按着,当前界面切换过来了,但是消息处理函数还没切换过来,这里需要特殊处理一下。

5.其他滑块样式(不是双滑块的)

需求以及思路:是这样子,要求右边要有遮盖,滑动块不能超过遮盖(这个其实好做),滑块的话要用其他控件遮挡,下面直接上代码:

这样滑动条样式

ui.controlSlider->setStyleSheet("QSlider::groove:horizontal{background:transparent;width:250px;height:16px;border-radius: 5px;border-image: url(:/res/ckImage/brightness_slider2x.png);background-repeat:none;}"//
			"QSlider::handle:horizontal{border-radius: 20px;width:  15px;height: 30px;margin-top: -8px;margin-bottom: -8px;border-image: url(:/res/ckImage/Brightnessbutton2x.png);background-repeat:none;}"//滑动条上滑块
			"QSlider{border: 24px solid transparent;border-left: 2px;border-right: 2px;border-radius: 15px;}");

 下面是遮盖处理以及思路

//当滑动条最大值不在范围内就会出现遮盖,否则不会
if (m_nMaxBv != 100) {
			labelMask = new QLabel(this);
//这里是计算qlabel大小,是根据滑块算的 m_nMaxBv是允许滑动最大值
			int width = (100 - m_nMaxBv) * 2.3 - (m_nMaxBv/40);
			labelMask->setFixedSize(width, 10);
			labelMask->adjustSize();
			labelMask->setWordWrap(true);
//因为只有x轴变化,y是固定值,这里259根据上面滑动条的宽度按调出来的
			labelMask->move(259 - width, 89);
//QLabel样式
			labelMask->setStyleSheet("background-repeat:repeat;background-position:right;background-color:#545454;\
			border-bottom-right-radius:5px;border-top-right-radius:5px;");
			labelMask->show();
		}
		else {
			if (labelMask)
				labelMask->hide();
		}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路奇怪

有钱出钱,没钱多出编程主意啊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值