aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorSacha Schutz <sacha@labsquare.org>2021-02-13 15:25:04 +0100
committerCristian Maureira-Fredes <cristian.maureira-fredes@qt.io>2021-04-15 14:33:35 +0000
commita434c1852ce3c040e2086568d7331c68b96ea38d (patch)
tree39f3a08777a933c2b5d6eb2b67dded4c35d205da /examples
parent4769e8fd93b2b434c6b38d755d1090eca5b62893 (diff)
Add a Paintbrush like example
A widget where user can draw on a canvas with different color. It is possible to save and load the canvas into a PNG file. This example teaches the user how to use QPainter outside the paintEvent using a QPixmap. Pick-to: 6.0 Task-number: PYSIDE-841 Change-Id: I8bbab68193894f4f5a6e101fa23fc65e6cb30864 Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'examples')
-rw-r--r--examples/widgets/painting/painter/painter.py238
-rw-r--r--examples/widgets/painting/painter/painter.pyproject3
2 files changed, 241 insertions, 0 deletions
diff --git a/examples/widgets/painting/painter/painter.py b/examples/widgets/painting/painter/painter.py
new file mode 100644
index 000000000..c9e2e4a10
--- /dev/null
+++ b/examples/widgets/painting/painter/painter.py
@@ -0,0 +1,238 @@
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://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$
+##
+#############################################################################
+
+from PySide6.QtWidgets import (
+ QWidget,
+ QMainWindow,
+ QApplication,
+ QFileDialog,
+ QStyle,
+ QColorDialog,
+)
+from PySide6.QtCore import QPoint, Qt, QDir, Slot, QStandardPaths
+from PySide6.QtGui import (
+ QMouseEvent,
+ QPaintEvent,
+ QPen,
+ QAction,
+ QPainter,
+ QColor,
+ QPixmap,
+ QIcon,
+ QKeySequence,
+)
+import sys
+
+
+class PainterWidget(QWidget):
+ """A widget where user can draw with their mouse
+
+ The user draws on a QPixmap which is itself paint from paintEvent()
+
+ """
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.setFixedSize(680, 480)
+ self.pixmap = QPixmap(self.size())
+ self.pixmap.fill(Qt.white)
+
+ self.previous_pos = None
+ self.painter = QPainter()
+ self.pen = QPen()
+ self.pen.setWidth(10)
+ self.pen.setCapStyle(Qt.RoundCap)
+ self.pen.setJoinStyle(Qt.RoundJoin)
+
+ def paintEvent(self, event: QPaintEvent):
+ """Override method from QWidget
+
+ Paint the Pixmap into the widget
+
+ """
+ painter = QPainter()
+ painter.begin(self)
+ painter.drawPixmap(0, 0, self.pixmap)
+ painter.end()
+
+ def mousePressEvent(self, event: QMouseEvent):
+ """Override from QWidget
+
+ Called when user clicks on the mouse
+
+ """
+ self.previous_pos = event.position().toPoint()
+ QWidget.mousePressEvent(self, event)
+
+ def mouseMoveEvent(self, event: QMouseEvent):
+ """Override method from QWidget
+
+ Called when user moves and clicks on the mouse
+
+ """
+ current_pos = event.position().toPoint()
+ self.painter.begin(self.pixmap)
+ self.painter.setRenderHints(QPainter.Antialiasing, True)
+ self.painter.setPen(self.pen)
+ self.painter.drawLine(self.previous_pos, current_pos)
+ self.painter.end()
+
+ self.previous_pos = current_pos
+ self.update()
+
+ QWidget.mouseMoveEvent(self, event)
+
+ def mouseReleaseEvent(self, event: QMouseEvent):
+ """Override method from QWidget
+
+ Called when user releases the mouse
+
+ """
+ self.previous_pos = None
+ QWidget.mouseReleaseEvent(self, event)
+
+ def save(self, filename: str):
+ """ save pixmap to filename """
+ self.pixmap.save(filename)
+
+ def load(self, filename: str):
+ """ load pixmap from filename """
+ self.pixmap.load(filename)
+ self.pixmap = self.pixmap.scaled(self.size(), Qt.KeepAspectRatio)
+ self.update()
+
+ def clear(self):
+ """ Clear the pixmap """
+ self.pixmap.fill(Qt.white)
+ self.update()
+
+
+class MainWindow(QMainWindow):
+ """An Application example to draw using a pen """
+
+ def __init__(self, parent=None):
+ QMainWindow.__init__(self, parent)
+
+ self.painter_widget = PainterWidget()
+ self.bar = self.addToolBar("Menu")
+ self.bar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
+ self._save_action = self.bar.addAction(
+ qApp.style().standardIcon(QStyle.SP_DialogSaveButton), "Save", self.on_save
+ )
+ self._save_action.setShortcut(QKeySequence.Save)
+ self._open_action = self.bar.addAction(
+ qApp.style().standardIcon(QStyle.SP_DialogOpenButton), "Open", self.on_open
+ )
+ self._open_action.setShortcut(QKeySequence.Open)
+ self.bar.addAction(
+ qApp.style().standardIcon(QStyle.SP_DialogResetButton),
+ "Clear",
+ self.painter_widget.clear,
+ )
+ self.bar.addSeparator()
+
+ self.color_action = QAction(self)
+ self.color_action.triggered.connect(self.on_color_clicked)
+ self.bar.addAction(self.color_action)
+
+ self.setCentralWidget(self.painter_widget)
+
+ self.set_color(Qt.black)
+
+ self.mime_type_filters = ["image/png", "image/jpeg"]
+
+ @Slot()
+ def on_save(self):
+
+ dialog = QFileDialog(self, "Save File")
+ dialog.setMimeTypeFilters(self.mime_type_filters)
+ dialog.setFileMode(QFileDialog.AnyFile)
+ dialog.setAcceptMode(QFileDialog.AcceptSave)
+ dialog.setDefaultSuffix("png")
+ dialog.setDirectory(
+ QStandardPaths.writableLocation(QStandardPaths.PicturesLocation)
+ )
+
+ if dialog.exec_() == QFileDialog.Accepted:
+ if dialog.selectedFiles():
+ self.painter_widget.save(dialog.selectedFiles()[0])
+
+ @Slot()
+ def on_open(self):
+
+ dialog = QFileDialog(self, "Save File")
+ dialog.setMimeTypeFilters(self.mime_type_filters)
+ dialog.setFileMode(QFileDialog.ExistingFile)
+ dialog.setAcceptMode(QFileDialog.AcceptOpen)
+ dialog.setDefaultSuffix("png")
+ dialog.setDirectory(
+ QStandardPaths.writableLocation(QStandardPaths.PicturesLocation)
+ )
+
+ if dialog.exec_() == QFileDialog.Accepted:
+ if dialog.selectedFiles():
+ self.painter_widget.load(dialog.selectedFiles()[0])
+
+ @Slot()
+ def on_color_clicked(self):
+
+ color = QColorDialog.getColor(Qt.black, self)
+ if color:
+ self.set_color(color)
+
+ def set_color(self, color: QColor = Qt.black):
+
+ # Create color icon
+ pix_icon = QPixmap(32, 32)
+ pix_icon.fill(color)
+
+ self.color_action.setIcon(QIcon(pix_icon))
+ self.painter_widget.pen.setColor(color)
+ self.color_action.setText(QColor(color).name())
+
+
+if __name__ == "__main__":
+
+ app = QApplication(sys.argv)
+
+ w = MainWindow()
+ w.show()
+ sys.exit(app.exec_())
diff --git a/examples/widgets/painting/painter/painter.pyproject b/examples/widgets/painting/painter/painter.pyproject
new file mode 100644
index 000000000..f47831696
--- /dev/null
+++ b/examples/widgets/painting/painter/painter.pyproject
@@ -0,0 +1,3 @@
+{
+ "files": ["painter.py"]
+}