怎么用qt、多线程实现koch分形雪花实时绘制

现阶段可以实现koch分形雪花,但是是一次性全部显示出来的,而不是慢慢生长出来 帮帮忙


main.cpp

Copy
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
mainwindow.h

Copy
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>

class FractalThread;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    void paintEvent(QPaintEvent *);

private:
    Ui::MainWindow *ui;
    FractalThread *thread;
    QMutex mutex;
    QWaitCondition condition;
    bool stop;

private slots:
    void on_startButton_clicked();
    void on_stopButton_clicked();
};

#endif // MAINWINDOW_H
mainwindow.cpp

Copy
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "fractalthread.h"
#include <QPainter>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    thread(nullptr),
    stop(false)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    mutex.lock();
    if (thread != nullptr)
    {
        painter.drawImage(0, 0, thread->image());
    }
    mutex.unlock();
}

void MainWindow::on_startButton_clicked()
{
    if (thread == nullptr)
    {
        thread = new FractalThread(this);
        thread->start();
    }
    else
    {
        mutex.lock();
        stop = false;
        condition.wakeAll();
        mutex.unlock();
    }
}

void MainWindow::on_stopButton_clicked()
{
    mutex.lock();
    stop = true;
    condition.wakeAll();
    mutex.unlock();
}

FractalThread

```c++
#ifndef FRACTALTHREAD_H
#define FRACTALTHREAD_H

#include <QObject>
#include <QThread>
#include <QImage>
#include <QMutex>
#include <QWaitCondition>

class FractalThread : public QThread
{
    Q_OBJECT

public:
    FractalThread(QObject *parent = nullptr);
    ~FractalThread();

    QImage image() const;

protected:
    void run();

private:
    QImage img;
    QMutex mutex;
    QWaitCondition condition;
    bool stop;

    void drawKoch(QPainter &painter, QPointF p1, QPointF p2, int level);

signals:
    void updated();
};

#endif // FRACTALTHREAD_H
fractalthread.cpp

Copy
#include "fractalthread.h"
#include <QPainter>
#include <cmath>

FractalThread::FractalThread(QObject *parent) :
    QThread(parent),
    img(800, 800, QImage::Format_RGB32),
    stop(false)
{
    img.fill(Qt::white);
}

FractalThread::~FractalThread()
{
    wait();
}

QImage FractalThread::image() const
{
    return img;
}

void FractalThread::run()
{
    QPainter painter(&img);
    painter.setRenderHint(QPainter::Antialiasing);

    QPointF p1(400, 50);
    QPointF p2(100, 650);
    QPointF p3(700, 650);
    drawKoch(painter, p1, p2, 5);
    drawKoch(painter, p2, p3, 5);
    drawKoch(painter, p3, p1, 5);

    mutex.lock();
    while (!stop)
    {
        condition.wait(&mutex);
    }
    mutex.unlock();
}

void FractalThread::drawKoch(QPainter &painter, QPointF p1, QPointF p2, int level)
{
    if (level == 0)
    {
        painter.drawLine(p1, p2);
    }
    else
    {
        QPointF p3 = p1 + (p2 - p1) / 3;
        QPointF p4 = p1 + (p2 - p1) * 2 / 3;
        QPointF p5 = p3 + QPointF(cos(M_PI / 3) * (p4 - p3).y() - sin(M_PI / 3) * (p4 - p3).x(),
                                   sin(M_PI / 3) * (p4 - p3).y() + cos(M_PI / 3) * (p4 - p3).x());

        drawKoch(painter, p1, p3, level - 1);
        drawKoch(painter, p3, p5, level - 1);
        drawKoch(painter, p5, p4, level - 1);
        drawKoch(painter, p4, p2, level - 1);
    }

    emit updated();
}

在运行程序时,点击“开始”按钮将启动线程并绘制Koch分形雪花,点击“停止”按钮将暂停线程。由于绘制线程和主线程是两个独立的线程,因此需要使用互斥量和条件变量来同步它们之间的操作。在绘制线程中,每绘制一次分形雪花就会发出更新信号,主线程接收到更新信号后会重新绘制窗口。这样就实现了Koch分形雪花的实时绘制效果。


#include "mainwindow.h"
#include <QtCore>
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QThread>


class KochSnowflake : public QWidget
{
public:
    KochSnowflake(QWidget *parent = nullptr) : QWidget(parent), level(0) {}

    void setLevel(int newLevel)
    {
        level = newLevel;
        update();
    }

protected:
    void paintEvent(QPaintEvent *event) override
    {
        Q_UNUSED(event);
        QPainter painter(this);
        drawSnowflake(painter, level, width() / 2, height() / 2, qMin(width(), height()) / 2 - 10);
    }

private:
    void drawSnowflake(QPainter &painter, int level, int x, int y, int size)
    {
        if (level == 0)
        {
            drawLine(painter, x, y, x + size, y);
            drawLine(painter, x + size, y, x + size / 2, y - size * qSqrt(3) / 2);
            drawLine(painter, x + size / 2, y - size * qSqrt(3) / 2, x, y);
        }
        else
        {
            int newSize = size / 3;

            drawSnowflake(painter, level - 1, x, y, newSize);
            drawSnowflake(painter, level - 1, x + newSize, y, newSize);
            drawSnowflake(painter, level - 1, x + newSize / 2, y - newSize * qSqrt(3) / 2, newSize);
            drawSnowflake(painter, level - 1, x + 2 * newSize, y, newSize);
            drawSnowflake(painter, level - 1, x + 2 * newSize, y + newSize * qSqrt(3), newSize);
            drawSnowflake(painter, level - 1, x + newSize, y + newSize * qSqrt(3), newSize);
            drawSnowflake(painter, level - 1, x + newSize / 2, y + newSize * qSqrt(3) / 2, newSize);
            drawSnowflake(painter, level - 1, x, y + newSize * qSqrt(3), newSize);
        }
    }

    void drawLine(QPainter &painter, int x1, int y1, int x2, int y2)
    {
        painter.drawLine(x1, y1, x2, y2);
    }

    int level;
};

class SnowflakeThread : public QThread
{
public:
    explicit SnowflakeThread(KochSnowflake *snowflake) : snowflake(snowflake) {}

    void setLevel(int level)
    {
        QMutexLocker locker(&mutex);
        this->level = level;
    }

protected:
    void run() override
    {
        while (!isInterruptionRequested())
        {
            QMutexLocker locker(&mutex);
            snowflake->setLevel(level);
            level = (level + 1) % 6;
            msleep(1000);
        }
    }

private:
    QMutex mutex;
    KochSnowflake *snowflake;
    int level = 0;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    KochSnowflake snowflake;
    SnowflakeThread snowflakeThread(&snowflake);
    snowflakeThread.start();

    snowflake.show();

    a.exec();

    snowflakeThread.requestInterruption();
    snowflakeThread.wait();

    return 0;
}