diff options
Diffstat (limited to 'examples/corelib/threads/mandelbrot.py')
-rw-r--r-- | examples/corelib/threads/mandelbrot.py | 163 |
1 files changed, 63 insertions, 100 deletions
diff --git a/examples/corelib/threads/mandelbrot.py b/examples/corelib/threads/mandelbrot.py index c95966119..4689813d4 100644 --- a/examples/corelib/threads/mandelbrot.py +++ b/examples/corelib/threads/mandelbrot.py @@ -1,44 +1,6 @@ - -############################################################################# -## -## Copyright (C) 2013 Riverbank Computing Limited. -## Copyright (C) 2016 The Qt Company Ltd. -## Contact: http://www.qt.io/licensing/ -## -## This file is part of the Qt for Python examples of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:BSD$ -## You may use this file under the terms of the BSD license as follows: -## -## "Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are -## met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in -## the documentation and/or other materials provided with the -## distribution. -## * Neither the name of The Qt Company Ltd nor the names of its -## contributors may be used to endorse or promote products derived -## from this software without specific prior written permission. -## -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2013 Riverbank Computing Limited. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause """PySide6 port of the corelib/threads/mandelbrot example from Qt v5.x, originating from PyQt""" @@ -47,7 +9,7 @@ import sys from PySide6.QtCore import (Signal, QMutex, QElapsedTimer, QMutexLocker, QPoint, QPointF, QSize, Qt, QThread, - QWaitCondition) + QWaitCondition, Slot) from PySide6.QtGui import QColor, QImage, QPainter, QPixmap, qRgb from PySide6.QtWidgets import QApplication, QWidget @@ -68,7 +30,7 @@ INFO_KEY = 'info' HELP = ("Use mouse wheel or the '+' and '-' keys to zoom. Press and " - "hold left mouse button to scroll.") + "hold left mouse button to scroll.") class RenderThread(QThread): @@ -91,7 +53,8 @@ class RenderThread(QThread): self.abort = False for i in range(RenderThread.colormap_size): - self.colormap.append(self.rgb_from_wave_length(380.0 + (i * 400.0 / RenderThread.colormap_size))) + self.colormap.append( + self.rgb_from_wave_length(380.0 + (i * 400.0 / RenderThread.colormap_size))) def stop(self): self.mutex.lock() @@ -102,18 +65,17 @@ class RenderThread(QThread): self.wait(2000) def render(self, centerX, centerY, scale_factor, resultSize): - locker = QMutexLocker(self.mutex) - - self._center_x = centerX - self._center_y = centerY - self._scale_factor = scale_factor - self._result_size = resultSize - - if not self.isRunning(): - self.start(QThread.LowPriority) - else: - self.restart = True - self.condition.wakeOne() + with QMutexLocker(self.mutex): + self._center_x = centerX + self._center_y = centerY + self._scale_factor = scale_factor + self._result_size = resultSize + + if not self.isRunning(): + self.start(QThread.LowPriority) + else: + self.restart = True + self.condition.wakeOne() def run(self): timer = QElapsedTimer() @@ -171,7 +133,8 @@ class RenderThread(QThread): if num_iterations < max_iterations: image.setPixel(x + half_width, y + half_height, - self.colormap[num_iterations % RenderThread.colormap_size]) + self.colormap[ + num_iterations % RenderThread.colormap_size]) all_black = False else: image.setPixel(x + half_width, y + half_height, qRgb(0, 0, 0)) @@ -185,7 +148,8 @@ class RenderThread(QThread): if elapsed > 2000: elapsed /= 1000 unit = 's' - text = f"Pass {curpass+1}/{NUM_PASSES}, max iterations: {max_iterations}, time: {elapsed}{unit}" + text = (f"Pass {curpass + 1}/{NUM_PASSES}, " + f"max iterations: {max_iterations}, time: {elapsed}{unit}") image.setText(INFO_KEY, text) self.rendered_image.emit(image, scale_factor) curpass += 1 @@ -253,45 +217,45 @@ class MandelbrotWidget(QWidget): self._info = '' def paintEvent(self, event): - painter = QPainter(self) - painter.fillRect(self.rect(), Qt.black) - - if self.pixmap.isNull(): + with QPainter(self) as painter: + painter.fillRect(self.rect(), Qt.black) + + if self.pixmap.isNull(): + painter.setPen(Qt.white) + painter.drawText(self.rect(), Qt.AlignCenter, + "Rendering initial image, please wait...") + return + + if self._cur_scale == self._pixmap_scale: + painter.drawPixmap(self._pixmap_offset, self.pixmap) + else: + scale_factor = self._pixmap_scale / self._cur_scale + new_width = int(self.pixmap.width() * scale_factor) + new_height = int(self.pixmap.height() * scale_factor) + new_x = self._pixmap_offset.x() + (self.pixmap.width() - new_width) / 2 + new_y = self._pixmap_offset.y() + (self.pixmap.height() - new_height) / 2 + + painter.save() + painter.translate(new_x, new_y) + painter.scale(scale_factor, scale_factor) + exposed, _ = painter.transform().inverted() + exposed = exposed.mapRect(self.rect()).adjusted(-1, -1, 1, 1) + painter.drawPixmap(exposed, self.pixmap, exposed) + painter.restore() + + text = HELP + if self._info: + text += ' ' + self._info + metrics = painter.fontMetrics() + text_width = metrics.horizontalAdvance(text) + + painter.setPen(Qt.NoPen) + painter.setBrush(QColor(0, 0, 0, 127)) + painter.drawRect((self.width() - text_width) / 2 - 5, 0, text_width + 10, + metrics.lineSpacing() + 5) painter.setPen(Qt.white) - painter.drawText(self.rect(), Qt.AlignCenter, - "Rendering initial image, please wait...") - return - - if self._cur_scale == self._pixmap_scale: - painter.drawPixmap(self._pixmap_offset, self.pixmap) - else: - scale_factor = self._pixmap_scale / self._cur_scale - new_width = int(self.pixmap.width() * scale_factor) - new_height = int(self.pixmap.height() * scale_factor) - new_x = self._pixmap_offset.x() + (self.pixmap.width() - new_width) / 2 - new_y = self._pixmap_offset.y() + (self.pixmap.height() - new_height) / 2 - - painter.save() - painter.translate(new_x, new_y) - painter.scale(scale_factor, scale_factor) - exposed, _ = painter.transform().inverted() - exposed = exposed.mapRect(self.rect()).adjusted(-1, -1, 1, 1) - painter.drawPixmap(exposed, self.pixmap, exposed) - painter.restore() - - text = HELP - if self._info: - text += ' ' + self._info - metrics = painter.fontMetrics() - text_width = metrics.horizontalAdvance(text) - - painter.setPen(Qt.NoPen) - painter.setBrush(QColor(0, 0, 0, 127)) - painter.drawRect((self.width() - text_width) / 2 - 5, 0, text_width + 10, - metrics.lineSpacing() + 5) - painter.setPen(Qt.white) - painter.drawText((self.width() - text_width) / 2, - metrics.leading() + metrics.ascent(), text) + painter.drawText((self.width() - text_width) / 2, + metrics.leading() + metrics.ascent(), text) def resizeEvent(self, event): self.thread.render(self._center_x, self._center_y, self._cur_scale, self.size()) @@ -340,6 +304,7 @@ class MandelbrotWidget(QWidget): delta_y = (self.height() - self.pixmap.height()) / 2 - self._pixmap_offset.y() self.scroll(delta_x, delta_y) + @Slot(QImage, float) def update_pixmap(self, image, scale_factor): if not self._last_drag_pos.isNull(): return @@ -354,15 +319,13 @@ class MandelbrotWidget(QWidget): def zoom(self, zoomFactor): self._cur_scale *= zoomFactor self.update() - self.thread.render(self._center_x, self._center_y, self._cur_scale, - self.size()) + self.thread.render(self._center_x, self._center_y, self._cur_scale, self.size()) def scroll(self, deltaX, deltaY): self._center_x += deltaX * self._cur_scale self._center_y += deltaY * self._cur_scale self.update() - self.thread.render(self._center_x, self._center_y, self._cur_scale, - self.size()) + self.thread.render(self._center_x, self._center_y, self._cur_scale, self.size()) if __name__ == '__main__': |