ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

自制Slider

2022-08-07 17:01:16  阅读:125  来源: 互联网

标签:include SliperNew int 自制 timer Slider QVector2D void


需求:
  1.绘制一个滑动条,在其上方绘制三角形,
  2.当鼠标进入(移动)到三角形区域时显示对应的标注值
  3.鼠标双击时三角形时,滑块移动到该位置
  4.鼠标单击滑块槽时,滑块也会移动到对应位置//待实现
技术点:
  1.实现鼠标单/双击
  2.绘制三角形
  3.判断某点是否位于三角形区域内

.h文件

#ifndef SLIPERNEW_H
#define SLIPERNEW_H

#include <QSlider>
#include <QStyle>
#include <QStylePainter>
#include <QStyleOptionSlider>
#include <QEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include <QVector2D>
#include <QVector>
#include <QMap>
#include <QTimer>
#include <QString>
#include <QToolTip>

#define cout qDebug() << "[" << __FILE__ << __LINE__ << "]:"
#define TXT(sr) QStringLiteral(sr)
#define TXT1(sr) QString(sr)

/*需求:
 * 1.绘制一个滑动条,在其上方绘制三角形,
 * 2.当鼠标进入(移动)到三角形区域时显示对应的标注值
 * 3.鼠标双击时三角形时,滑块移动到该位置
 * 4.鼠标单击滑块槽时,滑块也会移动到对应位置//待实现
 */


struct TimerInfo
{
    int m_iTimer;//时刻
    bool m_boolIsDraw;//是否绘制
    QString m_strComment;//标注信息
    QVector<QVector2D> m_vecCoordinate;//坐标

    TimerInfo(int timer, bool isDraw, QString comment)
    {
        m_iTimer = timer;
        m_boolIsDraw = isDraw;
        m_strComment = comment;
    }

    TimerInfo()
    {
        m_iTimer = 0;
        m_boolIsDraw = false;
        m_strComment = "";
    }
};

class SliperNew:public QSlider
{
public:
    SliperNew(QWidget *pParent = nullptr);


protected:
    virtual void paintEvent(QPaintEvent *ev) override;

    void mouseMoveEvent(QMouseEvent *event) override;
    //以下三个函数重载用于实现单双击
    void mouseReleaseEvent(QMouseEvent *event) override;
    void mousePressEvent(QMouseEvent *ev) override;
    void mouseDoubleClickEvent(QMouseEvent *ev) override;
public slots:
    void TimeOut();

private:
    void Init();

    void Draw();
    void DrawTriangle(int timer, int x, int y);//绘制timer对应的三角形图标
    bool PointInTriangle(QVector2D A,QVector2D B,QVector2D C,QVector2D P);//判断P点是否在三角形区域内
    int GetTimer(QVector2D P);//如果P点位于某三角形区域内,返回该区域对应时刻
    QPoint GetCurrenXY(int timer);//计算timer时刻对应的坐标系

private:
    QMap<int, TimerInfo> m_TimerInfo;
    int m_intMintimer, m_intMaxtimer;//最小,最大
    //以下变量主要用于实现单双击
    QTimer *m_timer;
    bool m_bLIsLPressed;
    bool m_blIShow;
};

#endif // SLIPERNEW_H

.cpp 文件

#include "SliperNew.h"
#include <QSlider>
#include <QDebug>
#include <QMessageBox>
#include <QFile>
SliperNew::SliperNew(QWidget *pParent):QSlider(pParent)
{
    setOrientation(Qt::Horizontal);
    setFocusPolicy(Qt::NoFocus);

    setRange(0, 100);

    //add szl
    //自定义窗口背景
    QPalette pal(this->palette());
    pal.setColor(QPalette::Background, Qt::blue);
    this->setAutoFillBackground(true);
    this->setPalette(pal);

    setOrientation(Qt::Horizontal);//设置进度条方向
//    setFixedSize(Length, Height);//设置进度条大小
    setFixedHeight(50);
//    setMinimum(Min);//进度条最小数值
//    setMaximum(Max);//进度条最大数值
    setSingleStep(1);//单步大小
//    setTickInterval(Tick);//刻度个数
    setTickPosition(QSlider::TicksAbove);//刻度曲线位置位置

    //设置样式
    //QSlider::groove:horizontal   背景样式
    //QSlider::handle:horizontal  滑块样式
    //QSlider::sub-page:horizontal 划过区域的样式
    setStyleSheet("QSlider::groove:horizontal{height:12px; left:0px; right:0px; border:0px; border-radius:6px; background:rgba(0,0,0,50);}\
                  QSlider::handle:horizontal{width:24px; background:#1644B0; border-radius:12px; margin:-6px 0px;}\
                  QSlider::sub-page:horizontal{background:#4C85FB; border:0px; border-radius:6px;}");


    this->setMouseTracking(true);//设置鼠标跟踪

    m_bLIsLPressed = false;
    m_blIShow = true;
    m_timer = new QTimer(this);
    connect(m_timer, &QTimer::timeout, this, [=](){
        TimeOut();

    });

    m_TimerInfo.clear();

    Init();
}

QPoint SliperNew::GetCurrenXY(int timer)
{
    QStyleOptionSlider opt;
    initStyleOption(&opt);
    // 获取滑块的大小
    QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
    int x = 0;
    int y = 0;

    x = round((double)((double)((double)(timer - minimum()) / (double)(maximum() - minimum())) * (double)(width() - handle.width()) + (double)(handle.width() / 2.0)));
    if (tickPosition() == TicksBothSides || tickPosition() == TicksAbove)
    {
       y = handle.top();
    }
    if (tickPosition() == TicksBothSides || tickPosition() == TicksBelow)
    {
        //                    int y = handle.bottom() + 5;
        //                    DrawTriangle(x, y);
        // to do
    }

    return QPoint(x, y);
}


//绘制函数
void SliperNew::Draw()
{
    if (!m_blIShow || m_intMaxtimer <= 0)
    {
        return;
    }

    for (auto bg = m_TimerInfo.begin(); bg != m_TimerInfo.end(); ++bg)
    {


        if (!bg->m_boolIsDraw)
        {
            continue;
        }
#if 0
        // draw tick marks
        // do this manually because they are very badly behaved with style sheets
        int interval = tickInterval();
        if (interval == 0)
        {
            interval = pageStep();
        }
#endif
        auto timer = bg->m_iTimer;
        if (tickPosition() != NoTicks)
        {
            auto XY = GetCurrenXY(timer);

            DrawTriangle(timer, XY.x(),  XY.y());
        }

    }

}

void SliperNew::paintEvent(QPaintEvent *ev)
{

    Draw();
    QSlider::paintEvent(ev);
}

void SliperNew::DrawTriangle(int timer, int x, int y)
{

        int x1 = x-5;
        int y1 = y-5;

        int x2 = x;
        int y2 = y;

        int x3 = x + 5;
        int y3 = y - 5;


        QVector2D v2dA(QPoint(x1, y1));
        QVector2D v2dB(QPoint(x2, y2));
        QVector2D v2dC(QPoint(x3, y3));

        QVector<QVector2D> vc;
        vc.append(v2dA);
        vc.append(v2dB);
        vc.append(v2dC);  

        m_TimerInfo[timer].m_vecCoordinate = vc;

        //绘制三角图标
        QPainter painter(this);
        painter.setPen(QColor("#999999"));
        painter.setBrush(QColor("#999999"));

        QPolygon triangle;
        triangle.setPoints(3, x1, y1, x2, y2, x3, y3);//三点坐标
        painter.drawPolygon(triangle);
        //填充颜色
        QPainterPath path;
        path.addPolygon(triangle);
        painter.fillPath(path, Qt::red);



#if 0
        //在对应刻度绘制字体,至少现在不需要
    QStylePainter p(this);
    QStyleOptionSlider opt;
    initStyleOption(&opt);

    // 因为刻度间隔比较密集,所以设置文本大小要小上几号,否则会重叠
    QFont f = font();
    f.setPointSize(f.pointSize() - 2);
    QFontMetrics metrics(f);
    p.setFont(f);

    if (isEnabled()) p.setPen(Qt::blue);
    else             p.setPen(QColor("#a5a294"));


    // 计算刻度文本数值的大小
    int tw = metrics.width(QString(" %1 ").arg(maximum()));
    int th = metrics.height();


    QRect rt = QRect(x - tw / 2, y - 4 - th, tw, th);
    //                    p.drawText(rt, QString::number(i / 10.0f, 'f', 1));

    p.drawText(rt, QString::number(3));//绘制文本


    //绘制滑动槽
    // draw the slider (this is basically copy/pasted from QSlider::paintEvent)
    opt.subControls = QStyle::SC_SliderGroove;
    p.drawComplexControl(QStyle::CC_Slider, opt);

    // draw the slider handle
    opt.subControls = QStyle::SC_SliderHandle;
    p.drawComplexControl(QStyle::CC_Slider, opt);

    #endif

}

bool SliperNew::PointInTriangle(QVector2D A,QVector2D B,QVector2D C,QVector2D P)//P鼠标当前的点位置
{

    QVector2D v0 = C - A;
    QVector2D v1 = B - A;
    QVector2D v2 = P - A;
    float dot00 = QVector2D::dotProduct(v0, v0);
    float dot01 = QVector2D::dotProduct(v0, v1);
    float dot02 = QVector2D::dotProduct(v0, v2);
    float dot11 = QVector2D::dotProduct(v1, v1);
    float dot12 = QVector2D::dotProduct(v1, v2);
    float inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);
    float u = (dot11 * dot02 - dot01 * dot12) * inverDeno ;
    if (u < 0 || u > 1)
    {
        return false;
    }
    float v = (dot00 * dot12 - dot01 * dot02) * inverDeno ;
    if (v < 0 || v > 1)
    {
        return false;
    }

    return u + v <= 1;

}

int SliperNew::GetTimer(QVector2D P)
{
    for (auto bg = m_TimerInfo.constBegin(); bg != m_TimerInfo.constEnd(); ++bg)
    {
        auto v3point = bg.value().m_vecCoordinate;
        QVector2D A;
        QVector2D B;
        QVector2D C;

        for (auto bv = v3point.begin(); bv != v3point.end(); ++bv)
        {
            if (A.isNull())
            {
                A = *bv;
            }
            else if(B.isNull())

            {
                B = *bv;
            }
            else if(C.isNull())
            {
                C = *bv;
            }

        }

        bool isIn = PointInTriangle(A,B,C,P);

        if (isIn)
        {
            return bg.key();
        }

    }

    return -1;
}


void SliperNew::mouseMoveEvent(QMouseEvent *event)
{
    float P_X = event->x();
    float P_Y = event->y();


    cout << "P_X" << P_X;

    QVector2D v2d;
    v2d.setX(P_X);
    v2d.setY(P_Y);

    int timer = GetTimer(v2d);

    if (-1 == timer)
    {
        //此时应该把提示信息置空,不过不置空也不影响
        //QToolTip::showText(QPoint(QCursor().pos().x(),QCursor().pos().y()),"", this);
        QToolTip::hideText();

        return;
    }
    cout << m_TimerInfo[timer].m_strComment;

    QToolTip::showText(QPoint(QCursor().pos().x(),QCursor().pos().y()),m_TimerInfo[timer].m_strComment, this);

    QSlider::mouseMoveEvent(event);

}



 //实现鼠标单击,双击,右击功能
void SliperNew::mousePressEvent(QMouseEvent *ev)
{
    if (ev->button() == Qt::LeftButton)
    {
        m_bLIsLPressed = true;
    }

}

void SliperNew::mouseReleaseEvent(QMouseEvent *event)
{

    if (event->button() == Qt::LeftButton)
    {
        if (m_bLIsLPressed)//如果已经点击过一次
        {
            m_timer->start(180);
        }
        m_bLIsLPressed = false;
    }
    else if (event->button() == Qt::RightButton)
    {
        cout << QStringLiteral("鼠标右键");
        QSlider::mouseReleaseEvent(event);
    }
}

void SliperNew::mouseDoubleClickEvent(QMouseEvent *ev)
{
    if (ev->button() == Qt::LeftButton)
    {
        m_timer->stop();
        //这里
        QVector2D vc2(ev->x(),ev->y());

        int timer = GetTimer(vc2);

        if (-1 == timer) return;

        this->setValue(timer);
    }

}

void SliperNew::TimeOut()
{

    m_timer->stop();
    cout << QString("鼠标左键单击");
    //计算鼠标当前值,并设置
    //to do
    this->setValue(0);
}


void SliperNew::Init()
{
    TimerInfo test1;
    test1.m_iTimer = 20;
    test1.m_boolIsDraw = true;
    test1.m_strComment = TXT1("标注20");
    m_TimerInfo.insert(20, test1);

    TimerInfo test2;
    test2.m_iTimer = 50;
    test2.m_boolIsDraw = true;
    test2.m_strComment = TXT1("标注50");
    m_TimerInfo.insert(50, test2);

    TimerInfo test3;
    test3.m_iTimer = 90;
    test3.m_boolIsDraw = true;
    test3.m_strComment = TXT1("标注90");
    m_TimerInfo.insert(90, test3);

    TimerInfo test4;
    test4.m_iTimer = 100;
    test4.m_boolIsDraw = true;
    test4.m_strComment = TXT1("标注100");
    m_TimerInfo.insert(100, test4);
}

参考链接:
原文实在找不到了,如有侵权请联系一下,谢谢-

标签:include,SliperNew,int,自制,timer,Slider,QVector2D,void
来源: https://www.cnblogs.com/gom-linwei/p/16559356.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有