qt雙滑塊

原本是從這個(gè)庫https://github.com/ThisIsClark/Qt-RangeSlider 去下載的卓研,但是實(shí)際使用中發(fā)現(xiàn)豎直滑動(dòng)條的時(shí)候茵汰,他的大值的滑塊在下面役衡,小值的滑塊在上面曹体,嚴(yán)重反直覺混稽,遂自己修改了一下借杰,變量名也根據(jù)自己便于理解的方式稍作修改了罗心,工作在qt6下面:

頭文件

RangeSlider.h

#pragma once

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

class RangeSlider : public QWidget
{
    Q_OBJECT
    Q_ENUMS(RangeSliderTypes)

public:
    enum Option
    {
        NoHandle = 0x0,
        // LeftHandle = 0x1,
        // RightHandle = 0x2,
        // DoubleHandles = LeftHandle | RightHandle

        MinHandle = 0x1,
        MaxHandle = 0x2,
        DoubleHandles = MinHandle | MaxHandle
    };
    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;

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

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

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

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

    void SetRange(float aMinimum, float 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 lowHandleRect() const;
    QRectF moreHandleRect() const;
    QRectF handleRect(float aValue) const;

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

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

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

    float mMinimum;
    float mMaximum;
    float mLowerValue;
    float mUpperValue;
    bool mLowHandlePressed;
    bool mMoreHandlePressed;
    float mInterval;
    float mDelta;
    QColor mBackgroudColorEnabled;
    QColor mBackgroudColorDisabled;
    QColor mBackgroudColor;
    Qt::Orientation orientation;
    Options type;
};

Q_DECLARE_OPERATORS_FOR_FLAGS(RangeSlider::Options)

源文件

RangeSlider


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

namespace
{

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

}

RangeSlider::RangeSlider(QWidget *aParent)
    : QWidget(aParent),
      mMinimum(0),
      mMaximum(100),
      mLowerValue(0),
      mUpperValue(100),
      mLowHandlePressed(false),
      mMoreHandlePressed(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),
      mLowHandlePressed(false),
      mMoreHandlePressed(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);
    painter.setRenderHint(QPainter::Antialiasing);
    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 MinHandleRect = lowHandleRect();
    if (type.testFlag(MinHandle))
        painter.drawRoundedRect(MinHandleRect, 2, 2);

    // Second value handle rect
    QRectF MaxHandleRect = moreHandleRect();
    if (type.testFlag(MaxHandle))
        painter.drawRoundedRect(MaxHandleRect, 2, 2);

    // Handles
    painter.setRenderHint(QPainter::Antialiasing, false);
    QRectF selectedRect(backgroundRect); // 藍(lán)色選中區(qū)域
    if (orientation == Qt::Horizontal)
    {
        selectedRect.setLeft((type.testFlag(MinHandle) ? MinHandleRect.right() : MinHandleRect.left()) + 0.5);
        selectedRect.setRight((type.testFlag(MaxHandle) ? MaxHandleRect.left() : MaxHandleRect.right()) - 0.5);
    }
    else
    {
        selectedRect.setBottom((type.testFlag(MinHandle) ? MinHandleRect.top() : MinHandleRect.bottom()) - 0.5);
        selectedRect.setTop((type.testFlag(MaxHandle) ? MaxHandleRect.bottom() : MaxHandleRect.top()) + 0.5);
    }
    QBrush selectedBrush(mBackgroudColor);
    painter.setBrush(selectedBrush);
    painter.drawRect(selectedRect);
}

/** ***************************************************************************
 * @brief 繪制對(duì)應(yīng)小值的滑塊
 * 水平的繪制在左邊吏砂,垂直的繪制在下面
 *
 * @return QRectF
 * ************************************************************************** */
QRectF RangeSlider::lowHandleRect() const
{
    float percentage{};
    if (orientation == Qt::Horizontal)
    {
        percentage = (mLowerValue - mMinimum) * 1.0 / mInterval;
        return handleRect(percentage * validLength() + scLeftRightMargin);
    }
    else
    {
        percentage = (mLowerValue - mMinimum) * 1.0 / mInterval;
        percentage = 1 - percentage;
        return handleRect(percentage * validLength() + scLeftRightMargin + (type.testFlag(MinHandle) ? scHandleSideLength : 0));
    }
    // return handleRect(percentage * validLength() + scLeftRightMargin);
}

/** ***************************************************************************
 * @brief 繪制對(duì)應(yīng)大值的滑塊
 * 水平繪制在右邊,垂直繪制在上面
 *
 * @return QRectF
 * ************************************************************************** */
QRectF RangeSlider::moreHandleRect() const
{
    float percentage{};

    if (orientation == Qt::Horizontal)
    {
        percentage = (mUpperValue - mMinimum) * 1.0 / mInterval;
        return handleRect(percentage * validLength() + scLeftRightMargin + (type.testFlag(MinHandle) ? scHandleSideLength : 0));
    }
    else
    {
        percentage = (mUpperValue - mMinimum) * 1.0 / mInterval;
        percentage = 1 - percentage;
        return handleRect(percentage * validLength() + scLeftRightMargin);
    }
    // return handleRect(percentage * validLength() + scLeftRightMargin + (type.testFlag(MinHandle) ? scHandleSideLength : 0));
}

/** ***************************************************************************
 * @brief 繪制滑塊
 *
 * @param[in] aValue
 * @return QRectF
 * ************************************************************************** */
QRectF RangeSlider::handleRect(float aValue) const
{
    if (orientation == Qt::Horizontal)
        return QRect(aValue, (height() - scHandleSideLength) / 2, scHandleSideLength, scHandleSideLength);
    else
        return QRect((width() - scHandleSideLength) / 2, aValue, scHandleSideLength, scHandleSideLength);
}

/** ***************************************************************************
 * @brief
 *
 * @param[in] aEvent
 * ************************************************************************** */
void RangeSlider::mousePressEvent(QMouseEvent *aEvent)
{

    if (aEvent->buttons() & Qt::LeftButton)
    {
        float posCheck, posMax, posValue, lowHandleRectPosValue, moreHandleRectPosValue;
        if (orientation == Qt::Horizontal)
        {
            posCheck = aEvent->pos().y();
            posMax = height();
            posValue = aEvent->pos().x();
            lowHandleRectPosValue = lowHandleRect().x();
            moreHandleRectPosValue = moreHandleRect().x();
        }
        else
        {
            posCheck = aEvent->pos().x();
            posMax = width();
            posValue = height() - aEvent->pos().y();
            lowHandleRectPosValue = height() - lowHandleRect().y();
            moreHandleRectPosValue = height() - moreHandleRect().y();
        }

        mMoreHandlePressed = moreHandleRect().contains(aEvent->pos());
        mLowHandlePressed = !mMoreHandlePressed && lowHandleRect().contains(aEvent->pos());
        if (mLowHandlePressed)
        {
            mDelta = posValue - (lowHandleRectPosValue + scHandleSideLength / 2);
        }
        else if (mMoreHandlePressed)
        {
            mDelta = posValue - (moreHandleRectPosValue + scHandleSideLength / 2);
        }

        if (posCheck >= 2 && posCheck <= posMax - 2)
        {
            float step = mInterval / 50;
            if (posValue < lowHandleRectPosValue)
                setLowerValue(mLowerValue - step);
            else if (((posValue > lowHandleRectPosValue + scHandleSideLength) || !type.testFlag(MinHandle)) && ((posValue < moreHandleRectPosValue) || !type.testFlag(MaxHandle)))
            {
                if (type.testFlag(DoubleHandles))
                    if (posValue - (lowHandleRectPosValue + scHandleSideLength) <
                        (moreHandleRectPosValue - (lowHandleRectPosValue + scHandleSideLength)) / 2)
                        setLowerValue((mLowerValue + step < mUpperValue) ? mLowerValue + step : mUpperValue);
                    else
                        setUpperValue((mUpperValue - step > mLowerValue) ? mUpperValue - step : mLowerValue);
                else if (type.testFlag(MinHandle))
                    setLowerValue((mLowerValue + step < mUpperValue) ? mLowerValue + step : mUpperValue);
                else if (type.testFlag(MaxHandle))
                    setUpperValue((mUpperValue - step > mLowerValue) ? mUpperValue - step : mLowerValue);
            }
            else if (posValue > moreHandleRectPosValue + scHandleSideLength)
                setUpperValue(mUpperValue + step);
        }
    }
}

/** ***************************************************************************
 * @brief
 *
 * @param[in] aEvent
 * ************************************************************************** */
void RangeSlider::mouseMoveEvent(QMouseEvent *aEvent)
{

    if (aEvent->buttons() & Qt::LeftButton)
    {
        float posValue, lowHandleRectPosValue, moreHandleRectPosValue;
        if (orientation == Qt::Horizontal)
        {
            posValue = aEvent->pos().x();
            lowHandleRectPosValue = lowHandleRect().x();
            moreHandleRectPosValue = moreHandleRect().x();
        }
        else
        {
            posValue = height() - aEvent->pos().y();
            lowHandleRectPosValue = height() - lowHandleRect().y();
            moreHandleRectPosValue = height() - moreHandleRect().y();
        }

        if (mLowHandlePressed && type.testFlag(MinHandle))
        {
            if (posValue - mDelta + scHandleSideLength / 2 <= moreHandleRectPosValue)
            {
                setLowerValue((posValue - mDelta - scLeftRightMargin - scHandleSideLength / 2) * 1.0 / validLength() * mInterval + mMinimum);
            }
            else
            {
                setLowerValue(mUpperValue);
            }
        }
        else if (mMoreHandlePressed && type.testFlag(MaxHandle))
        {
            if (lowHandleRectPosValue + 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);

    mLowHandlePressed = false;
    mMoreHandlePressed = 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);
}

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

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

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

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

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

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

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

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

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

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

    mLowerValue = aLowerValue;
    emit lowerValueChanged(mLowerValue);
    emit updownChanged(mLowerValue, mUpperValue);

    update();
}

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

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

    mUpperValue = aUpperValue;
    emit upperValueChanged(mUpperValue);
    emit updownChanged(mLowerValue, mUpperValue);

    update();
}

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

    setLowerValue(mMinimum);
    setUpperValue(mMaximum);

    emit rangeChanged(mMinimum, mMaximum);
}

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

    setLowerValue(mMinimum);
    setUpperValue(mMaximum);

    emit rangeChanged(mMinimum, mMaximum);
}

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

void RangeSlider::SetRange(float aMinimum, float mMaximum)
{
    setMinimum(aMinimum);
    setMaximum(mMaximum);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拳魁,一起剝皮案震驚了整個(gè)濱河市惶桐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌潘懊,老刑警劉巖姚糊,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異授舟,居然都是意外死亡救恨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門岂却,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忿薇,“玉大人裙椭,你說我怎么就攤上這事∈鸷疲” “怎么了揉燃?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)筋栋。 經(jīng)常有香客問我炊汤,道長(zhǎng),這世上最難降的妖魔是什么弊攘? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任抢腐,我火速辦了婚禮,結(jié)果婚禮上襟交,老公的妹妹穿的比我還像新娘迈倍。我一直安慰自己,他們只是感情好捣域,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布啼染。 她就那樣靜靜地躺著,像睡著了一般焕梅。 火紅的嫁衣襯著肌膚如雪迹鹅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天贞言,我揣著相機(jī)與錄音斜棚,去河邊找鬼。 笑死该窗,一個(gè)胖子當(dāng)著我的面吹牛弟蚀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播酗失,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼粗梭,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了级零?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤滞乙,失蹤者是張志新(化名)和其女友劉穎奏纪,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斩启,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡序调,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了兔簇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片发绢。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡硬耍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出边酒,到底是詐尸還是另有隱情经柴,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布墩朦,位于F島的核電站坯认,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏氓涣。R本人自食惡果不足惜牛哺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望劳吠。 院中可真熱鬧引润,春花似錦、人聲如沸痒玩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凰荚。三九已至燃观,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間便瑟,已是汗流浹背缆毁。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留到涂,地道東北人脊框。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像践啄,于是被迫代替她去往敵國和親浇雹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容