Files
scuc-qt-course/docs/teaching/examples/mandelbrot_renderer/mandelbrot_widget.h
T
张宗平 6773f9b29e Day4 教学示例:Mandelbrot 分形渲染器(QPainter 绘图 + 多线程 + 事件处理综合演示)
三段式对比直击 Day4 slides「主线程耗时=冻结」痛点:主线程渲染冻结 / 后台单线程不卡但慢 / 后台多线程不卡且快。
- QThreadPool + QRunnable 分水平条带并行,排队信号槽回传,epoch 版本号防过期覆盖
- wheelEvent 缩放(鼠标为锚)+ mouseEvent 拖拽平移 + paintEvent 画 QImage
- 子目录自带独立 CMakeLists.txt,可单独构建/共享(双模式约定同 lineedit_eye_toggle)
- 配套 README(概念/走读/双构建/5 踩坑点/练习)+ 设计规格
- 已验证:独立工程 offscreen 运行 exit=0;主工程构建 exit=0(w64devkit g++16 + mingw73 Qt5.14.2)

注:主工程 examples/CMakeLists.txt 的接入(mandelbrot + lineedit_eye_toggle + qdialog + themes 原子接入)与顶层 CMakeLists 本地调试改动未一并提交,待整体确认后单独提交。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 09:01:29 +08:00

60 lines
2.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================================
// mandelbrot_widget —— Day4 Mandelbrot 渲染器的交互与渲染调度主体(QWidget)
// 职责:
// * paintEvent : 把累积 QImage 一次性画到窗口(QPainter 绘图知识点)
// * wheelEvent/mouse* : 滚轮缩放(以鼠标为锚)、左键拖拽平移(事件处理知识点)
// * scheduleRender() : 切水平条带丢 QThreadPool 并行算(多线程知识点)
// * onStripReady() : 收条带、拼图、版本号防过期、耗时显示
// * onRenderOnMainThread() : 「主线程渲染」按钮——同步算整帧,演示事件循环被
// 占用即界面冻结(直击 Day4 slides「主线程耗时=冻结」痛点)
// * onToggleThreadMode() : 复用同一套分块逻辑,切线程池大小,对比单/多线程加速比
// ============================================================================
#ifndef MANDELBROT_WIDGET_H
#define MANDELBROT_WIDGET_H
#include <QElapsedTimer>
#include <QImage>
#include <QPoint>
#include <QWidget>
#include "mandelbrot_strip_task.h" // MandelViewport / MandelPalette
class QLabel;
class MandelbrotWidget : public QWidget {
Q_OBJECT
public:
explicit MandelbrotWidget(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*) override;
void wheelEvent(QWheelEvent*) override;
void mousePressEvent(QMouseEvent*) override;
void mouseMoveEvent(QMouseEvent*) override;
void mouseReleaseEvent(QMouseEvent*) override;
void resizeEvent(QResizeEvent*) override;
private slots:
void onStripReady(quint64 epoch, int stripIndex, QImage strip);
void onRenderOnMainThread(); // 卡死演示
void onToggleThreadMode(); // 单/多线程切换
private:
void scheduleRender(); // ++epoch + 分块丢池
MandelViewport vp_;
MandelPalette pal_;
QImage pixmap_; // 累积画布(离屏 QImagepaintEvent 外对它构造 QPainter 合法)
quint64 epoch_ = 0; // 渲染版本号:新视口令旧结果作废丢弃(防过期覆盖)
int stripsTotal_ = 0;
int stripsDone_ = 0;
QElapsedTimer timer_;
bool multiThread_ = true;
int threadCount_ = 0;
bool dragging_ = false;
QPoint lastMouse_;
QLabel* label_ = nullptr;
};
#endif // MANDELBROT_WIDGET_H