Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QPainter Performance
Forum Updated to NodeBB v4.3 + New Features

QPainter Performance

Scheduled Pinned Locked Moved Unsolved General and Desktop
10 Posts 4 Posters 1.2k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • I Offline
    I Offline
    inthewind2004
    wrote on last edited by
    #1

    I want to implement whiteboard functions, and one of the important functions is to draw lines. During the implementation, I ran into a problem: if I keep drawing (lines containing more than 10,000 points) on the Widget,the Widget is very stuck. Is there a good solution?
    Here's part of my code:
    void RenderArea::drawMyImage()
    {
    QPainter painter;
    painter.begin(&mImage);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setBrush(brush);
    painter.setPen(penLists[9]);

    QMapIterator<int, QList<QPointF> *> it(m_id2PointList);
    
    while(it.hasNext()) {
        auto item = it.next();
        QList<QPointF> *pointList = item.value();
        this->bezier = false;
        if (this->bezier && pointList->length() > 3) {
            QList<QPointF> points = *pointList;
            QPainterPath path = getBezierPath(points);
            painter.drawPath(path);
            continue;
        }
        painter.drawPolyline(pointList->toVector().data(), pointList->length());
    }
    painter.end();
    

    }

    bool RenderArea::event(QEvent *event)
    {
    switch (event->type()) {
    case QEvent::MouseButtonPress:
    case QEvent::MouseMove:
    case QEvent::MouseButtonRelease:
    case QEvent::TouchBegin:
    case QEvent::TouchUpdate:
    case QEvent::TouchEnd:
    {
    const auto touchPoints = static_cast<QTouchEvent >(event)->points();
    for (const QTouchEvent::TouchPoint &touchPoint : touchPoints) {
    int id = touchPoint.id();
    QList<QPointF>
    p_listPoint = m_id2PointList[id];

            switch (touchPoint.state()) {
            case QEventPoint::Released: 
                m_id2PointList.remove(id);
    
                if (p_listPoint) {
                    m_completePointLists.push_back(p_listPoint);
                    m_completePenLists.push_back(pen);
                }
                continue;
    
            case QEventPoint::Pressed:
                pListPoint = new QList<QPointF>();
                p_listPoint  =  new QList<QPointF>();
                m_id2PointList[touchPoint.id()] = p_listPoint;
                
            default:
                { 
                    QPointF point = touchPoint.position();                    
                    p_listPoint->push_back(point);
                    drawMyImage();
                    if (p_listPoint->size() >= 2){
                        QPointF pointA = p_listPoint->at(p_listPoint->size() - 2);
                        QPointF pointB = p_listPoint->at(p_listPoint->size() - 1);
                        QRect rect(qMin(pointA.x(), pointB.x()), qMin(pointA.y(), pointB.y()),
                                   qAbs(pointA.x() - pointB.x()), qAbs(pointA.y() - pointB.y()));
                        rect.adjust(-10 , -10 , 10, 10);
                        update(rect);
                    } else {
                        QRect rect(point.x(), point.y(), 0, 0);
                        rect.adjust(-10 , -10 , 10, 10);
                        update(rect);
                    }                    
                }
    
                break;
            }
        }
        break;
    }
    default:
        return QWidget::event(event);
    }
    return true;
    

    }

    void RenderArea::paintEvent(QPaintEvent *event)
    {
    QPainter painter(this);
    const QRect rect = event->rect();
    painter.drawImage(rect.topLeft(), mImage, rect);
    }

    A 1 Reply Last reply
    0
    • I inthewind2004

      I want to implement whiteboard functions, and one of the important functions is to draw lines. During the implementation, I ran into a problem: if I keep drawing (lines containing more than 10,000 points) on the Widget,the Widget is very stuck. Is there a good solution?
      Here's part of my code:
      void RenderArea::drawMyImage()
      {
      QPainter painter;
      painter.begin(&mImage);
      painter.setRenderHint(QPainter::Antialiasing, true);
      painter.setBrush(brush);
      painter.setPen(penLists[9]);

      QMapIterator<int, QList<QPointF> *> it(m_id2PointList);
      
      while(it.hasNext()) {
          auto item = it.next();
          QList<QPointF> *pointList = item.value();
          this->bezier = false;
          if (this->bezier && pointList->length() > 3) {
              QList<QPointF> points = *pointList;
              QPainterPath path = getBezierPath(points);
              painter.drawPath(path);
              continue;
          }
          painter.drawPolyline(pointList->toVector().data(), pointList->length());
      }
      painter.end();
      

      }

      bool RenderArea::event(QEvent *event)
      {
      switch (event->type()) {
      case QEvent::MouseButtonPress:
      case QEvent::MouseMove:
      case QEvent::MouseButtonRelease:
      case QEvent::TouchBegin:
      case QEvent::TouchUpdate:
      case QEvent::TouchEnd:
      {
      const auto touchPoints = static_cast<QTouchEvent >(event)->points();
      for (const QTouchEvent::TouchPoint &touchPoint : touchPoints) {
      int id = touchPoint.id();
      QList<QPointF>
      p_listPoint = m_id2PointList[id];

              switch (touchPoint.state()) {
              case QEventPoint::Released: 
                  m_id2PointList.remove(id);
      
                  if (p_listPoint) {
                      m_completePointLists.push_back(p_listPoint);
                      m_completePenLists.push_back(pen);
                  }
                  continue;
      
              case QEventPoint::Pressed:
                  pListPoint = new QList<QPointF>();
                  p_listPoint  =  new QList<QPointF>();
                  m_id2PointList[touchPoint.id()] = p_listPoint;
                  
              default:
                  { 
                      QPointF point = touchPoint.position();                    
                      p_listPoint->push_back(point);
                      drawMyImage();
                      if (p_listPoint->size() >= 2){
                          QPointF pointA = p_listPoint->at(p_listPoint->size() - 2);
                          QPointF pointB = p_listPoint->at(p_listPoint->size() - 1);
                          QRect rect(qMin(pointA.x(), pointB.x()), qMin(pointA.y(), pointB.y()),
                                     qAbs(pointA.x() - pointB.x()), qAbs(pointA.y() - pointB.y()));
                          rect.adjust(-10 , -10 , 10, 10);
                          update(rect);
                      } else {
                          QRect rect(point.x(), point.y(), 0, 0);
                          rect.adjust(-10 , -10 , 10, 10);
                          update(rect);
                      }                    
                  }
      
                  break;
              }
          }
          break;
      }
      default:
          return QWidget::event(event);
      }
      return true;
      

      }

      void RenderArea::paintEvent(QPaintEvent *event)
      {
      QPainter painter(this);
      const QRect rect = event->rect();
      painter.drawImage(rect.topLeft(), mImage, rect);
      }

      A Offline
      A Offline
      Asperamanca
      wrote on last edited by
      #2

      @inthewind2004
      What is the lifetime of m_id2PointList and mImage?

      If m_id2PointList just gets longer and longer, no need to wonder about performance issues. QPainter is pretty optimized, but it is single-threaded and doesn't use GPU support. And Bezier lines are not the simplest thing to draw.

      If you only ever want to add lines, then store the image, and only paint new lines on top of the existing image. That should be pretty fast.

      1 Reply Last reply
      1
      • I Offline
        I Offline
        inthewind2004
        wrote on last edited by
        #3

        Thank you for your advice. It was very helpful.
        But, I found the following statement to be ineffective on the image:
        painter.setRenderHint(QPainter::Antialiasing, true);
        How do I set it?

        jsulmJ M 2 Replies Last reply
        0
        • I inthewind2004

          Thank you for your advice. It was very helpful.
          But, I found the following statement to be ineffective on the image:
          painter.setRenderHint(QPainter::Antialiasing, true);
          How do I set it?

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @inthewind2004 said in QPainter Performance:

          How do I set it?

          I don't understand the question. You're already setting it.

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • I inthewind2004

            Thank you for your advice. It was very helpful.
            But, I found the following statement to be ineffective on the image:
            painter.setRenderHint(QPainter::Antialiasing, true);
            How do I set it?

            M Offline
            M Offline
            mpergand
            wrote on last edited by
            #5

            @inthewind2004 said in QPainter Performance:

            Thank you for your advice. It was very helpful.
            But, I found the following statement to be ineffective on the image:
            painter.setRenderHint(QPainter::Antialiasing, true);
            How do I set it?

            try:
            painter.setRenderHint(QPainter::SmoothPixmapTransform);

            I 1 Reply Last reply
            0
            • M mpergand

              @inthewind2004 said in QPainter Performance:

              Thank you for your advice. It was very helpful.
              But, I found the following statement to be ineffective on the image:
              painter.setRenderHint(QPainter::Antialiasing, true);
              How do I set it?

              try:
              painter.setRenderHint(QPainter::SmoothPixmapTransform);

              I Offline
              I Offline
              inthewind2004
              wrote on last edited by
              #6

              @mpergand Thanks.
              I try to use the sentence above, but the effect is not very good.
              Antialiasing has no effect on QImage?
              But I didn't see similar conclusions in the help document.

              M 1 Reply Last reply
              0
              • I inthewind2004

                @mpergand Thanks.
                I try to use the sentence above, but the effect is not very good.
                Antialiasing has no effect on QImage?
                But I didn't see similar conclusions in the help document.

                M Offline
                M Offline
                mpergand
                wrote on last edited by mpergand
                #7

                @inthewind2004 said in QPainter Performance:

                Antialiasing has no effect on QImage?

                Don't know,
                try to convert to pixmap with:
                QPixelMap::fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor)

                I 1 Reply Last reply
                0
                • M mpergand

                  @inthewind2004 said in QPainter Performance:

                  Antialiasing has no effect on QImage?

                  Don't know,
                  try to convert to pixmap with:
                  QPixelMap::fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor)

                  I Offline
                  I Offline
                  inthewind2004
                  wrote on last edited by
                  #8

                  @mpergand I've tried, but the result is the same

                  M 1 Reply Last reply
                  0
                  • I inthewind2004

                    @mpergand I've tried, but the result is the same

                    M Offline
                    M Offline
                    mpergand
                    wrote on last edited by
                    #9

                    @inthewind2004
                    Antialiasing works as expected with QImage ...

                    Show us what result you have with your image.

                    I 1 Reply Last reply
                    0
                    • M mpergand

                      @inthewind2004
                      Antialiasing works as expected with QImage ...

                      Show us what result you have with your image.

                      I Offline
                      I Offline
                      inthewind2004
                      wrote on last edited by
                      #10

                      @mpergand Thanks.
                      I drew two circles on QImage, one with anti-aliasing on and one with anti-aliasing off. As a result, anti-aliasing is effective on QImage . The code is as follows:
                      void RenderArea::drawMyEllipse()
                      {
                      QPainter painter(&mImage);
                      //painter.setRenderHint(QPainter::Antialiasing, true);
                      painter.setCompositionMode(QPainter::CompositionMode_Source);
                      painter.setPen(QPen(Qt::red, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
                      painter.drawEllipse(300, 300, 300, 300);
                      update();
                      }
                      The result:
                      1.Antialiasing off
                      Drawing-无抗锯齿.png

                      2.Antialiasing on
                      Drawing-抗锯齿.png

                      However, the Bezier curve drawn on QImage is not very smooth (compared to QWidget).The source code:
                      void RenderArea::drawToImage(MyLine *line)
                      {
                      QPainter painter(&mImage);
                      painter.setRenderHint(QPainter::Antialiasing, true);
                      painter.setCompositionMode(QPainter::CompositionMode_Source);
                      painter.setPen(QPen(Qt::red, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
                      QPainterPath path = line->makeStrokePath(5);
                      painter.fillPath(path,Qt::red);
                      QRectF rect = path.boundingRect();
                      update(rect.x(), rect.y(), rect.width(), rect.height());
                      }
                      The result:
                      Drawing-曲线-抗锯齿.png

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved