欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

【Qt】Q多线程开发—多线程应用示例分析(Mandelbrot)

时间:2023-06-05
Qt-多线程应用示例分析(Mandelbrot) 文章目录

Qt-多线程应用示例分析(Mandelbrot)一、写在前面二、RendThread类的定义

(2-1)run()函数实现(2-2)render()函数的实现 三、MandelbrotWidget类的定义四、总结 一、写在前面

​ 本文章讨论内容是:关于Qt的多线程应用,创建线程的方法是:子类化QThread创建线程,重载run()函数实现多线程。

​ (注)本文所有代码出自官方示例《Mandelbrot Example》

​ 《Mandelbrot Example》示例包含两个类:

1、RenderThread是一个QThread子类,用于呈现Mandelbrot集合。
  2、MandelbrotWidget是一个QWidget子类,用于在屏幕上显示Mandelbrot集合,并绑定鼠标缩放和滚动事件处理功能。

二、RendThread类的定义

#include #include #include #include QT_BEGIN_NAMESPACEclass QImage;QT_END_NAMESPACE//! [0]class RenderThread : public QThread{ Q_OBJECTpublic: RenderThread(QObject *parent = nullptr); ~RenderThread(); void render(double centerX, double centerY, double scaleFactor, QSize resultSize);signals: void renderedImage(const QImage &image, double scaleFactor);protected: void run() override;private: uint rgbFromWaveLength(double wave); QMutex mutex; QWaitCondition condition; double centerX; double centerY; double scaleFactor; QSize resultSize; bool restart; bool abort; enum { ColormapSize = 512 }; uint colormap[ColormapSize];};

​ 1、该类继承了QThread,因此它能够在单独的线程中运行。除了构造函数和析构函数外,render()是唯一的公共函数。每当线程渲染一个图像时,都会发出renderedImage()信号。renderedImage()信号将与MandelbrotWidget类的updatePixmap槽函数相连接,用于更新QPixmap。以便于MandelbrotWidget类的paintEvent()绘图事件函数对经过RenderThread线程渲染后的Pixmap绘制。如下代码片段:

connect(&thread, &RenderThread::renderedImage,this, &MandelbrotWidget::updatePixmap);

2、在QThread子类中重新实现受保护的run()函数,在线程启动时自动调用它。

​ 3、在私有部分中,有一个QMutex、一个QWaitCondition和一些其他的数据成员。互斥锁保护另一个数据成员。

(2-1)run()函数实现

void RenderThread::run(){ forever { mutex.lock(); QSize resultSize = this->resultSize; double scaleFactor = this->scaleFactor; double centerX = this->centerX; double centerY = this->centerY; mutex.unlock(); int halfWidth = resultSize.width() / 2; int halfHeight = resultSize.height() / 2; QImage image(resultSize, QImage::Format_RGB32); const int NumPasses = 8; int pass = 0; while (pass < NumPasses) { const int MaxIterations = (1 << (2 * pass + 6)) + 32; const int Limit = 4; bool allBlack = true; for (int y = -halfHeight; y < halfHeight; ++y) { if (restart) break; if (abort) return; uint *scanLine = reinterpret_cast(image.scanLine(y + halfHeight)); double ay = centerY + (y * scaleFactor); for (int x = -halfWidth; x < halfWidth; ++x) { double ax = centerX + (x * scaleFactor); double a1 = ax; double b1 = ay; int numIterations = 0; do { ++numIterations; double a2 = (a1 * a1) - (b1 * b1) + ax; double b2 = (2 * a1 * b1) + ay; if ((a2 * a2) + (b2 * b2) > Limit) break; ++numIterations; a1 = (a2 * a2) - (b2 * b2) + ax; b1 = (2 * a2 * b2) + ay; if ((a1 * a1) + (b1 * b1) > Limit) break; } while (numIterations < MaxIterations); if (numIterations < MaxIterations) { *scanLine++ = colormap[numIterations % ColormapSize]; allBlack = false; } else { *scanLine++ = qRgb(0, 0, 0); } } }//for END        if (allBlack && pass == 0) { pass = 4; } else { if (!restart) emit renderedImage(image, scaleFactor);   ++pass; } }//While END mutex.lock(); if (!restart) condition.wait(&mutex); restart = false; mutex.unlock(); }}

(2-2)render()函数的实现

void RenderThread::render(double centerX, double centerY, double scaleFactor, QSize resultSize){ QMutexLocker locker(&mutex); this->centerX = centerX; this->centerY = centerY; this->scaleFactor = scaleFactor; this->resultSize = resultSize; if (!isRunning()) { start(LowPriority); } else { restart = true; condition.wakeOne(); }}

三、MandelbrotWidget类的定义

class MandelbrotWidget : public QWidget{ Q_OBJECTpublic: MandelbrotWidget(QWidget *parent = nullptr);protected: void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; void keyPressEvent(QKeyEvent *event) override;#if QT_ConFIG(wheelevent) void wheelEvent(QWheelEvent *event) override;#endif void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override;private slots: void updatePixmap(const QImage &image, double scaleFactor); void zoom(double zoomFactor);private: void scroll(int deltaX, int deltaY); RenderThread thread; QPixmap pixmap; QPoint pixmapOffset; QPoint lastDragPos; double centerX; double centerY; double pixmapScale; double curScale;};

四、总结

​ 1、RendThread类与MandelbrotWidget类通过信号和槽机制进行关联:用于更新MandelbrotWidget类中所使用的Pixmap数据,然后在paintEvent()绘图事件函数中进行绘制。

​ 2、MandelbrotWidget类通过调用RendThread类的render(double centerX, double centerY, double scaleFactor, QSize resultSize)成员函数向RendThread类中传递数据并启动RendThread类线程进行计算。

​ 3、Qt中Widgets部件(例如QPushButton、QLabel等)不能在其他线程中创建,只能在GUI线程中创建。

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。