0

我有一个特定的目标:画一个路网。所以我有很多点(x,y),我想连接它们(使用 drawLine 函数)。因为他们的数量(大约 2-3 百万)我需要在另一个线程中做,所以我应该怎么做?我有一个特殊的绘图区——QLabel。我试图通过主线程中的 QPixmap 来完成它,一切都很好,但是当我尝试通过另一个线程中的信号/插槽来完成它时,没有图像出现:(

实际上,当我将坐标转换为 GUI 坐标时,它们会变成小数,所以我不知道如何绘制它们,因为 drawLine 函数具有整数参数:(int x1, int y1, int x2, int y2)。

这就是我创建另一个线程的方式(我只需要运行一个函数,所以这是我认为的最佳方式) QtConcurrent::run(this,&MainWindow::parseXML)

希望你能帮助我,因为我会发疯 %)

PS我读过多线程绘图不支持QPixmap。所以现在我不知道该怎么做。
QPainter can be used in a thread to paint onto QImage, QPrinter, and QPicture paint devices. Painting onto QPixmaps and QWidgets is not supported. On Mac OS X the automatic progress dialog will not be displayed if you are printing from outside the GUI thread.

4

4 回答 4

7

如果您需要在 Qt GUI 线程以外的线程中进行绘画,请执行以下操作:

  1. 在您的非 GUI 线程中,创建一个 QImage 对象
  2. 使用 QPainter 绘制到 QImage 对象中
  3. 使用 QApplication::postEvent 或排队的信号/槽连接以线程安全的方式将 QImage 对象传递给主线程
  4. 主线程现在可以将 QImage 对象转换为 QPixmap(这会比较快),然后像往常一样显示它。
于 2013-04-29T20:18:45.400 回答
1

您显然正在寻找一个QGraphicsView(或者最好QQuickView是如果您关心性能并且正在使用 Qt5)。这正是 Qt 为此目的提供的解决方案。

对于您的问题-Qt 中无法在单独的线程中进行绘画;任何小部件类都不能从另一个线程触及。提议的invokeMethod调用实际上是一个异步回调,它在主线程中排队等待执行。您可以生成 a QImage,将其传递给 GUI 线程并让 GUI 使用它,但我强烈建议您使用场景图 (the QGraphicsView),因为它正是为此目的而设计和优化的。

于 2013-04-30T08:53:49.810 回答
0

虽然这是非常糟糕的做法 - 从工作线程中更新 GUI 线程,并且您应该通过信号槽(使用连接类型 -queued)真正做到这一点,但您仍然可以通过以下方式更新 GUIQMetaObject::invokeMethod()

您必须在工作线程中运行每个函数,通过invokeMethod(). 例如 - 在你的主类中,添加类似的函数void MainWindow::drawLine(int x1, int y1, int x2, int y2),它将在你的 QImage 上画线。在您的线程中,您可以像这样调用该函数:

QMetaObject::invokeMethod(this,"drawLine", Q_ARG(int,x1), Q_ARG(int,y1), Q_ARG(int,x2), Q_ARG(int,y2));
于 2013-04-29T21:19:01.500 回答
0

最简单的方法是同时将绘图分布在多个图像上,然后合成图像(也是同时),最后将它们提交到 gui 上进行绘制。

这可以使用QtConcurrent::map图像序列来完成。map 仿函数绘制到特定于当前线程的图像中 - 例如 via QThreadStorage。在分配时,对该图像的引用也可以存储在仿函数内的列表中。函子当然必须比对QtConcurrent::map. 一旦map返回,函子内列表中的图像可以成对地异步组合,直到只剩下一个图像。然后将该图像提交给显示小部件。

如果要避免全尺寸图像合成,那么类似的方法将起作用,但线必须分组到空间组中,即与覆盖要绘制区域的一些矩形相交的线。要充分利用所有内核,您需要说 2-3 倍于QThread::idealThreadCount(). 然后将这些组中的每一个在其子图像上的绘画视为并发任务,提交给QtConcurrent::run. 完成所有任务后,图像将提交给显示小部件,该小部件按顺序将它们绘制在其后备存储上。

后备存储上的图像绘制也可以是多线程的,完整示例请参见此答案。一般来说,图像的宽度需要是(CPU 缓存线大小/4,因为我们使用 32 位像素)的倍数。在后备存储上绘制这些图像是完全可并行的。

于 2018-06-22T07:38:49.383 回答