首页 > 其他分享 >QT之自制Slider

QT之自制Slider

时间:2022-10-31 18:14:51浏览次数:77  
标签:include QT 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);
}

原文:https://www.cnblogs.com/gom-linwei/p/16559356.html

标签:include,QT,SliperNew,int,自制,timer,Slider,QVector2D,void
From: https://www.cnblogs.com/xiaohai123/p/16845241.html

相关文章

  • Qt设置运行时动态库路径的几点说明
    Qt设置运行时动态库路径的几点说明Qt教程 2022-04-1601:00随着需求的不断增加,程序不断变大,用到的动态库也越来越多,到了发布程序的时候你会发现和可执行文件同一目录下......
  • linuxdeployqt QT打包
    一、环境硬件平台:英伟达Xavier系统版本:Ubuntu18.04.3LTSQt版本:Qt5.9.5二、步骤1、下载linuxdeployqt源码:下载地址:Releases·probonopd/linuxdeployqt·GitH......
  • HarmonyOS系统中内核实现MQTT连接华为云的方法
       大家好,今天主要和大家聊一聊,如何使用MQTT连接华为云平台的方法目录​​第一:MQTT通信基本原理​​​​第二:华为IOT平台API​​​​第三:华为IOT平台初始化​​​​第......
  • Qt应用程序接口和插件的创建详细过程
    Qt应用程序接口:包含类定义的头文件(*.h),该类定义中一般只包含纯虚函数的声明。Qt应用程序插件:继承自指定类和接口的C++类,该类实现了接口中定义的纯虚函数。 ------------......
  • Qt+Opencv应用程序计时/度量(测量速度)的三种方法
    OpenCV计时/度量方法(测量速度),尽量远离经验法则,请试着用你的测量或者任何可信语言的测量参考作为你的经验法则的来源:可以使用OPenCV中的TickMeter类或getTickFrequency函数......
  • 配置pyqt5工具designer,pyuic, pyRCC
    前提:安装好pyQT5后打开pycharm-->file-->setting-->externaltools,-->点+号新建:name:QTdesignerGroup:ExternalToolsprogram:你的项目地址\venv\Lib\site-package......
  • Qt图形视图框架--精确选中连接线
    一、前言在使用Qt图形视图框架进行组态软件开发过程中,我通过继承自QGraphicsPathItem自定义的连接线图元Arrow,发现点选连接线特别不灵敏;classArrow:publicQGraphicsPath......
  • Qt图形视图框架--图元总结
    文章目录​​一、基类QGraphicsItem​​​​二、内部图元​​​​2.1、椭圆图元--QGraphicsEllipseItem​​​​2.2、线段图元--QGraphicsLineItem​​​​2.3、路径图元--Q......
  • Qt之悬浮球菜单
    目录一、概述二、效果展示三、实现代码1、菜单项2、悬浮球3、关键点四、相关文章原文链接:Qt之悬浮球菜单一、概述最近想做一个炫酷的悬浮式菜单,考虑到菜单展开和美观,所......
  • 工业网关BL110实现西门子S7-400 PLC 接入金鸽MQTT云平台
    LAN接口的配置COM口采集西门子S7-400PLC的配置工业智能网关BL110一共有一个LAN接口,一个WAN接口,可以通过LAN接口采集数据,通过WAN接口接入局域网,设置过程不一样,WAN接口可......