快速绘制数千个rects

时间:2016-04-20 15:47:17

标签: qt drawing scene

在QT(大约100,000或更多)中绘制数千$.doTimeout( 100, function(){ if ( $("#description" ).text() != "") { $("#description" ).text() == "Product A" ? $("#desc-a").css("display","inline") : $("#desc-b").css("display","inline"); return false; } return true; }); 的正确方法是什么?

我试过了:

  • 使用rects的{​​{1}}进行简单。
  • 将对象绘制到paintEvent(),然后将此图片绘制到QWidget
  • 使用QImage(也许我没有正确使用它,我只是将QWidget添加到了场景中)

每次绘画都很慢,而且我对如何做到这一点没有更多的想法(也许使用opengl / directx,但这听起来并不是一个好主意)。我知道存在应用程序,所以应该有一些方法。

编辑:

我想知道QGraphicsScene是如何运作的?是否有可能填充一些rects数组并将其传递给drawRects()会更好?

2 个答案:

答案 0 :(得分:0)

第一个技巧是在单独的线程中绘制到QImage,然后将其传递到主线程。这不会使它更快,但它会使它不会阻止GUI线程。

// https://github.com/KubaO/stackoverflown/tree/master/questions/threaded-paint-36748972
#include <QtWidgets>
#include <QtConcurrent>

class Widget : public QWidget {
   Q_OBJECT
   QImage m_image;
   bool m_pendingRender { false };
   Q_SIGNAL void hasNewRender(const QImage &);
   // Must be thread-safe, we can't access the widget directly!
   void paint() {
      QImage image{2048, 2048, QImage::Format_ARGB32_Premultiplied};
      image.fill(Qt::white);
      QPainter p(&image);
      for (int i = 0; i < 100000; ++i) {
         QColor c{rand() % 256, rand() % 256, rand() % 256};
         p.setBrush(c);
         p.setPen(c);
         p.drawRect(rand() % 2048, rand() % 2048, rand() % 100, rand() % 100);
      }
      emit hasNewRender(image);
   }
   void paintEvent(QPaintEvent *) {
      QPainter p(this);
      p.drawImage(0, 0, m_image);
   }
public:
   Widget(QWidget * parent = 0) : QWidget(parent) {
      this->setAttribute(Qt::WA_OpaquePaintEvent);
      setMinimumSize(200, 200);
      connect(this, &Widget::hasNewRender, this, [this](const QImage & img) {
         m_image = img;
         m_pendingRender = false;
         update();
      });
      refresh();
   }
   Q_SLOT void refresh() {
      if (!m_pendingRender) {
         m_pendingRender = true;
         QtConcurrent::run([this] { paint(); });
      }
   }
};

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   Widget w;
   QPushButton button{"Refresh", &w};
   button.connect(&button, &QPushButton::clicked, &w, [&w]{ w.refresh(); });
   w.show();
   return app.exec();
}

#include "main.moc"

作为一个单独的问题,您可以将绘图分割为多个并行作业,方法是将每个作业的画家剪切到共享图像的子区域,并注意完全剪切的矩形绘制是无操作,部分剪切的是只会填充他们影响的像素。

答案 1 :(得分:0)

我发现的解决方案:

创建uint32_t数组,其中可以包含widget的所有像素,并使用memcpy()填充它。使用此数组创建QImage并使用drawImage()进行显示。 它可以有一些优化,例如(for profiler)合并rects,它们是继续的(开始时间秒等于第一个结束)。不要画出超出时间范围的rects。也许跳过太小rects。 为了绘制文本,工具提示等内容,您仍然可以使用Qt函数。 对于最简单的alpha混合,你可以只取现有值,将它们循环混合并写入混合值,或者使用SIMD来实现这一点。

当然对于更复杂的形状,它会更难绘制,但我认为它仍然比使用Qt函数更快。