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集合,并绑定鼠标缩放和滚动事件处理功能。
#include
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
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线程中创建。