Mandelbrot Example: Use High DPI scaling
Create the pixmap with a device pixel ratio set. Change-Id: I7f7e90aec4d117304852f050be70e14a0c6bf69d Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
2c390e85cf
commit
a719c630f1
@ -187,6 +187,10 @@
|
|||||||
generate more and more precise (and computationally expensive)
|
generate more and more precise (and computationally expensive)
|
||||||
approximations of the fractal.
|
approximations of the fractal.
|
||||||
|
|
||||||
|
We create a high resolution pixmap by applying the device
|
||||||
|
pixel ratio to the target size (see
|
||||||
|
\l{Drawing High Resolution Versions of Pixmaps and Images}).
|
||||||
|
|
||||||
If we discover inside the loop that \c restart has been set to \c
|
If we discover inside the loop that \c restart has been set to \c
|
||||||
true (by \c render()), we break out of the loop immediately, so
|
true (by \c render()), we break out of the loop immediately, so
|
||||||
that the control quickly returns to the very top of the outer
|
that the control quickly returns to the very top of the outer
|
||||||
@ -273,12 +277,21 @@
|
|||||||
\snippet threads/mandelbrot/mandelbrotwidget.cpp 8
|
\snippet threads/mandelbrot/mandelbrotwidget.cpp 8
|
||||||
|
|
||||||
If the pixmap has the right scale factor, we draw the pixmap directly onto
|
If the pixmap has the right scale factor, we draw the pixmap directly onto
|
||||||
the widget. Otherwise, we scale and translate the \l{Coordinate
|
the widget.
|
||||||
System}{coordinate system} before we draw the pixmap. By reverse mapping
|
|
||||||
the widget's rectangle using the scaled painter matrix, we also make sure
|
Otherwise, we create a preview pixmap to be shown until the calculation
|
||||||
that only the exposed areas of the pixmap are drawn. The calls to
|
finishes and translate the \l{Coordinate System}{coordinate system}
|
||||||
QPainter::save() and QPainter::restore() make sure that any painting
|
accordingly.
|
||||||
performed afterwards uses the standard coordinate system.
|
|
||||||
|
Since we are going to use transformations on the painter
|
||||||
|
and use an overload of QPainter::drawPixmap() that does not support
|
||||||
|
high resolution pixmaps in that case, we create a pixmap with device pixel
|
||||||
|
ratio 1.
|
||||||
|
|
||||||
|
By reverse mapping the widget's rectangle using the scaled painter matrix,
|
||||||
|
we also make sure that only the exposed areas of the pixmap are drawn.
|
||||||
|
The calls to QPainter::save() and QPainter::restore() make sure that any
|
||||||
|
painting performed afterwards uses the standard coordinate system.
|
||||||
|
|
||||||
\snippet threads/mandelbrot/mandelbrotwidget.cpp 9
|
\snippet threads/mandelbrot/mandelbrotwidget.cpp 9
|
||||||
|
|
||||||
|
@ -55,6 +55,8 @@
|
|||||||
//! [0]
|
//! [0]
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
MandelbrotWidget widget;
|
MandelbrotWidget widget;
|
||||||
widget.show();
|
widget.show();
|
||||||
|
@ -107,18 +107,22 @@ void MandelbrotWidget::paintEvent(QPaintEvent * /* event */)
|
|||||||
//! [6] //! [7]
|
//! [6] //! [7]
|
||||||
} else {
|
} else {
|
||||||
//! [7] //! [8]
|
//! [7] //! [8]
|
||||||
|
auto previewPixmap = qFuzzyCompare(pixmap.devicePixelRatioF(), qreal(1))
|
||||||
|
? pixmap
|
||||||
|
: pixmap.scaled(pixmap.size() / pixmap.devicePixelRatioF(), Qt::KeepAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
double scaleFactor = pixmapScale / curScale;
|
double scaleFactor = pixmapScale / curScale;
|
||||||
int newWidth = int(pixmap.width() * scaleFactor);
|
int newWidth = int(previewPixmap.width() * scaleFactor);
|
||||||
int newHeight = int(pixmap.height() * scaleFactor);
|
int newHeight = int(previewPixmap.height() * scaleFactor);
|
||||||
int newX = pixmapOffset.x() + (pixmap.width() - newWidth) / 2;
|
int newX = pixmapOffset.x() + (previewPixmap.width() - newWidth) / 2;
|
||||||
int newY = pixmapOffset.y() + (pixmap.height() - newHeight) / 2;
|
int newY = pixmapOffset.y() + (previewPixmap.height() - newHeight) / 2;
|
||||||
|
|
||||||
painter.save();
|
painter.save();
|
||||||
painter.translate(newX, newY);
|
painter.translate(newX, newY);
|
||||||
painter.scale(scaleFactor, scaleFactor);
|
painter.scale(scaleFactor, scaleFactor);
|
||||||
|
|
||||||
QRectF exposed = painter.transform().inverted().mapRect(rect()).adjusted(-1, -1, 1, 1);
|
QRectF exposed = painter.transform().inverted().mapRect(rect()).adjusted(-1, -1, 1, 1);
|
||||||
painter.drawPixmap(exposed, pixmap, exposed);
|
painter.drawPixmap(exposed, previewPixmap, exposed);
|
||||||
painter.restore();
|
painter.restore();
|
||||||
}
|
}
|
||||||
//! [8] //! [9]
|
//! [8] //! [9]
|
||||||
@ -139,7 +143,7 @@ void MandelbrotWidget::paintEvent(QPaintEvent * /* event */)
|
|||||||
//! [10]
|
//! [10]
|
||||||
void MandelbrotWidget::resizeEvent(QResizeEvent * /* event */)
|
void MandelbrotWidget::resizeEvent(QResizeEvent * /* event */)
|
||||||
{
|
{
|
||||||
thread.render(centerX, centerY, curScale, size());
|
thread.render(centerX, centerY, curScale, size(), devicePixelRatioF());
|
||||||
}
|
}
|
||||||
//! [10]
|
//! [10]
|
||||||
|
|
||||||
@ -208,8 +212,9 @@ void MandelbrotWidget::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
pixmapOffset += event->pos() - lastDragPos;
|
pixmapOffset += event->pos() - lastDragPos;
|
||||||
lastDragPos = QPoint();
|
lastDragPos = QPoint();
|
||||||
|
|
||||||
int deltaX = (width() - pixmap.width()) / 2 - pixmapOffset.x();
|
const auto pixmapSize = pixmap.size() / pixmap.devicePixelRatioF();
|
||||||
int deltaY = (height() - pixmap.height()) / 2 - pixmapOffset.y();
|
int deltaX = (width() - pixmapSize.width()) / 2 - pixmapOffset.x();
|
||||||
|
int deltaY = (height() - pixmapSize.height()) / 2 - pixmapOffset.y();
|
||||||
scroll(deltaX, deltaY);
|
scroll(deltaX, deltaY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,7 +239,7 @@ void MandelbrotWidget::zoom(double zoomFactor)
|
|||||||
{
|
{
|
||||||
curScale *= zoomFactor;
|
curScale *= zoomFactor;
|
||||||
update();
|
update();
|
||||||
thread.render(centerX, centerY, curScale, size());
|
thread.render(centerX, centerY, curScale, size(), devicePixelRatioF());
|
||||||
}
|
}
|
||||||
//! [17]
|
//! [17]
|
||||||
|
|
||||||
@ -244,6 +249,6 @@ void MandelbrotWidget::scroll(int deltaX, int deltaY)
|
|||||||
centerX += deltaX * curScale;
|
centerX += deltaX * curScale;
|
||||||
centerY += deltaY * curScale;
|
centerY += deltaY * curScale;
|
||||||
update();
|
update();
|
||||||
thread.render(centerX, centerY, curScale, size());
|
thread.render(centerX, centerY, curScale, size(), devicePixelRatioF());
|
||||||
}
|
}
|
||||||
//! [18]
|
//! [18]
|
||||||
|
@ -76,13 +76,14 @@ RenderThread::~RenderThread()
|
|||||||
|
|
||||||
//! [2]
|
//! [2]
|
||||||
void RenderThread::render(double centerX, double centerY, double scaleFactor,
|
void RenderThread::render(double centerX, double centerY, double scaleFactor,
|
||||||
QSize resultSize)
|
QSize resultSize, double devicePixelRatio)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&mutex);
|
QMutexLocker locker(&mutex);
|
||||||
|
|
||||||
this->centerX = centerX;
|
this->centerX = centerX;
|
||||||
this->centerY = centerY;
|
this->centerY = centerY;
|
||||||
this->scaleFactor = scaleFactor;
|
this->scaleFactor = scaleFactor;
|
||||||
|
this->devicePixelRatio = devicePixelRatio;
|
||||||
this->resultSize = resultSize;
|
this->resultSize = resultSize;
|
||||||
|
|
||||||
if (!isRunning()) {
|
if (!isRunning()) {
|
||||||
@ -99,8 +100,10 @@ void RenderThread::run()
|
|||||||
{
|
{
|
||||||
forever {
|
forever {
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
const QSize resultSize = this->resultSize;
|
const double devicePixelRatio = this->devicePixelRatio;
|
||||||
const double scaleFactor = this->scaleFactor;
|
const QSize resultSize = this->resultSize * devicePixelRatio;
|
||||||
|
const double requestedScaleFactor = this->scaleFactor;
|
||||||
|
const double scaleFactor = requestedScaleFactor / devicePixelRatio;
|
||||||
const double centerX = this->centerX;
|
const double centerX = this->centerX;
|
||||||
const double centerY = this->centerY;
|
const double centerY = this->centerY;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
@ -111,6 +114,7 @@ void RenderThread::run()
|
|||||||
//! [4] //! [5]
|
//! [4] //! [5]
|
||||||
int halfHeight = resultSize.height() / 2;
|
int halfHeight = resultSize.height() / 2;
|
||||||
QImage image(resultSize, QImage::Format_RGB32);
|
QImage image(resultSize, QImage::Format_RGB32);
|
||||||
|
image.setDevicePixelRatio(devicePixelRatio);
|
||||||
|
|
||||||
const int NumPasses = 8;
|
const int NumPasses = 8;
|
||||||
int pass = 0;
|
int pass = 0;
|
||||||
@ -162,7 +166,7 @@ void RenderThread::run()
|
|||||||
pass = 4;
|
pass = 4;
|
||||||
} else {
|
} else {
|
||||||
if (!restart)
|
if (!restart)
|
||||||
emit renderedImage(image, scaleFactor);
|
emit renderedImage(image, requestedScaleFactor);
|
||||||
//! [5] //! [6]
|
//! [5] //! [6]
|
||||||
++pass;
|
++pass;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,8 @@ public:
|
|||||||
RenderThread(QObject *parent = nullptr);
|
RenderThread(QObject *parent = nullptr);
|
||||||
~RenderThread();
|
~RenderThread();
|
||||||
|
|
||||||
void render(double centerX, double centerY, double scaleFactor, QSize resultSize);
|
void render(double centerX, double centerY, double scaleFactor, QSize resultSize,
|
||||||
|
double devicePixelRatio);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void renderedImage(const QImage &image, double scaleFactor);
|
void renderedImage(const QImage &image, double scaleFactor);
|
||||||
@ -85,6 +86,7 @@ private:
|
|||||||
double centerX;
|
double centerX;
|
||||||
double centerY;
|
double centerY;
|
||||||
double scaleFactor;
|
double scaleFactor;
|
||||||
|
double devicePixelRatio;
|
||||||
QSize resultSize;
|
QSize resultSize;
|
||||||
bool restart = false;
|
bool restart = false;
|
||||||
bool abort = false;
|
bool abort = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user