QT实现实时跟随鼠标绘制彩色线条

QT实现实时跟随鼠标绘制彩色线条

鼠标按下时执行画图,如图效果:
请添加图片描述
开发环境QT6.5 MSVC2019 windows

实现难点:只用QPainter的drawPath方法只能绘制单色的线条,绘制彩色线条参考的代码:彩色线条,并且项目的GPU、CPU分配有限,不能占用太多。

实现原理,通过继承QOpenGLWidget调用paintGL的GPU绘图,避免大量绘图占用CPU的问题,在实时计算时放入单独的线程中执行,定时刷新页面数据,同时运用双缓冲机制绘图,保证界面不会卡顿。

核心代码如下:

class MyCalculator : public QObject
{
    Q_OBJECT

public:
    MyCalculator()
    {
        annotationPath.clear();
        oldPath.clear();
        img=QImage(1,100,QImage::Format_ARGB32);
        QPainter imgp(&img);
        QLinearGradient gradient = QLinearGradient(QPointF(0,0),QPointF(0,100));
        gradient.setColorAt(0,Qt::red);
        gradient.setColorAt(0.333,Qt::green);
        gradient.setColorAt(0.666,Qt::blue);
        gradient.setColorAt(1,Qt::red);
        imgp.fillRect(img.rect(),gradient);

        pixmap = QPixmap(1080,720);
        pixmap.fill (Qt :: transparent);
        state=true;
    }

    void setPath(QPainterPath p)
    {
        QMutexLocker lock(&mutexs);
        annotationPath=p;
    };
    QPixmap getImage()
    {
        return pixmap;
    }
    void killThread()
    {
        state=false;
    }
public slots:
    void calculate()
    {
        while(state)
        {
            QThread::msleep(10);
            QMutexLocker lock(&mutexs);

            if(annotationPath.length() == 0)
            {
                QThread::msleep(10);
                continue;
            }
            // qDebug()<<"算法开始计算"<<QTime::currentTime();
            //颜色表,先绘制到img,再根据坐标取颜色值
            //根据路径长度和分片长度来取路径百分比坐标和颜色
            //注意:pointAtPercent比较耗时
            auto first=annotationPath;

            double len = first.length();
            int step = 10;

            int index=oldPath.length();
            pt1 =first.pointAtPercent(index/len);
            QPointF pt2=pt1;

            QPainter painter(&pixmap);
            QPen pen;
            pen.setColor(Qt::red);
            pen.setWidth(8);

            for(int i = index  ;i<len;i+=step)
            {
                pt1=pt2;
                int i2 = i+step;
                //根据分片长度获取两端的坐标

                pt2=first.pointAtPercent(i2<len?(i2/len):1.0);  //获取百分比的点,i2如果>len的长度说明到达了顶点

                //两点距离过长说明是到了另一段子路径上
                //那就往前找当前子路径的末尾

                while(QVector2D(pt1).distanceToPoint(QVector2D(pt2))>step+1){ //两点间距
                    i2--;
                    pt2=first.pointAtPercent(i2<len?(i2/len):1.0);
                }
                //从颜色表取对应的颜色值
                QColor color2=img.pixelColor(0,((i+step)/step+0)%100);
                pen.setColor(color2);
                painter.setPen(pen); //CPU
                painter.drawLine(pt1,pt2); //性能

                if(!list.contains(SBrushPointF(color2,pt1,pt2)))
                {
                    list<<SBrushPointF(color2,pt1,pt2);
                }
                else
                {
                    continue;
                }

                //根据两端颜色设置渐变,然后填充该分片

                //下一个子路径的端点
                if(i2!=i+step){
                    i2++;
                    pt2=first.pointAtPercent(i2<len?(i2/len):1.0);
                }
            }
            qDebug()<<"绘制结束"<<QTime::currentTime()<<first.length()<<list.size();
            oldPath=annotationPath;
            annotationPath.clear();

            emit finished(pixmap);
        }
    }
signals:
    void finished(QPixmap);
    void endExit();
public:
    QPainterPath annotationPath; //标注路径
    QPainterPath oldPath;
    QList<SBrushPointF> list;
    QMutex mutexs;
    QImage img;
    QPointF pt1;
    QPixmap  pixmap;
    std::atomic_bool state;
};

    thread = new QThread();
    // 创建计算对象
    calculator = new MyCalculator();
    // 将计算对象移动到子线程中
    calculator->moveToThread(thread);
    // 连接信号和槽
    connect(thread, &QThread::started, calculator, &MyCalculator::calculate);
    connect(calculator, &MyCalculator::finished, this, &MainWindow::onCalculateFinish,Qt::QueuedConnection);
    // 启动子线程
    thread->start();

void MainWindow::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0, 0, 0, 0);

    QPainter painter(this);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
    painter.drawPixmap(0,0,pixmap);
}

完整代码见链接:[下载链接](https://download.csdn.net/download/m0_52215787/88561856)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值