Painter Example#
Simple painter application based on Qt Widgets.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from PySide6.QtWidgets import (
QWidget,
QMainWindow,
QApplication,
QFileDialog,
QStyle,
QColorDialog,
)
from PySide6.QtCore import Qt, 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
"""
with QPainter(self) as painter:
painter.drawPixmap(0, 0, self.pixmap)
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), # noqa: F821
"Save", self.on_save
)
self._save_action.setShortcut(QKeySequence.Save)
self._open_action = self.bar.addAction(
qApp.style().standardIcon(QStyle.SP_DialogOpenButton), # noqa: F821
"Open", self.on_open
)
self._open_action.setShortcut(QKeySequence.Open)
self.bar.addAction(
qApp.style().standardIcon(QStyle.SP_DialogResetButton), # noqa: F821
"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.color = Qt.black
self.set_color(self.color)
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(self.color, self)
if color:
self.set_color(color)
def set_color(self, color: QColor = Qt.black):
self.color = color
# Create color icon
pix_icon = QPixmap(32, 32)
pix_icon.fill(self.color)
self.color_action.setIcon(QIcon(pix_icon))
self.painter_widget.pen.setColor(self.color)
self.color_action.setText(QColor(self.color).name())
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec())