The given code below is derived from another question on SO. It displays a QMainWindow
with 4 QGraphicsView
to draw with the mouse in it, a QPushButton
to clear the 4 QGraphicsView
, and a QPushButton
to get a new random color for drawing.
Goal: I would like to change the color of future drawings without changing the color of existing drawings.
Attempt: Changing the color of a QPen
object immediately changed the color of the drawings already drawn. Therefore I created new GraphicsPathItem
objects with new QPen
objects with the new color to avoid this.
Problem: After a color change the color of existing drawings in a QGraphicsView
changes as soon as you draw something in it again.
How can this problem be solved?
main.py
import sys
from random import choice
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPathItem
from PyQt5.QtGui import QPainterPath, QPen, QColor
from PyQt5.QtCore import Qt
from PyQt5.uic import loadUi
# Based on code from https://stackoverflow.com/a/44248794/7481773
class MainWindow(QMainWindow):
COLORS = ("black", "red", "green", "blue", "yellow")
def __init__(self):
super().__init__()
loadUi("mainwindow.ui", self)
self.color = "black"
self.layouts = (self.verticalLayout_top_left, self.verticalLayout_top_right,
self.verticalLayout_bottom_left, self.verticalLayout_bottom_right)
self._views = []
for layout in self.layouts:
graphics_view = GraphicsView(self.color)
self._views.append(graphics_view)
layout.addWidget(graphics_view)
self.clear_button.clicked.connect(self.clear_views)
self.color_button.clicked.connect(self.update_color)
def _get_new_random_color(self):
new_colors = list(self.COLORS)
new_colors.remove(self.color)
return choice(new_colors)
def clear_views(self):
for view in self._views:
view.clear_view()
def update_color(self):
new_color = self._get_new_random_color()
self.color = new_color
for view in self._views:
view.new_item(new_color)
class GraphicsView(QGraphicsView):
def __init__(self, color):
super().__init__()
self.start = None
self.end = None
self.item = None
self.setScene(QGraphicsScene())
self.path = QPainterPath()
self.new_item(color)
self.contents_rect = self.contentsRect()
self.setSceneRect(0, 0, self.contents_rect.width(), self.contents_rect.height())
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
def clear_view(self):
try:
self.path.clear()
except AttributeError:
self.path = QPainterPath()
self.item.setPath(self.path)
def new_item(self, color):
self.item = GraphicsPathItem(color)
self.scene().addItem(self.item)
def mousePressEvent(self, event):
self.start = self.mapToScene(event.pos())
self.path.moveTo(self.start)
def mouseMoveEvent(self, event):
self.end = self.mapToScene(event.pos())
self.path.lineTo(self.end)
self.start = self.end
self.item.setPath(self.path)
class GraphicsPathItem(QGraphicsPathItem):
def __init__(self, color):
super().__init__()
self.pen = QPen()
self.pen.setColor(QColor(color))
self.pen.setWidth(5)
self.setPen(self.pen)
def main():
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
app.exec_()
del main_window, app
if __name__ == "__main__":
main()
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Paint and Clear</string>
</property>
<property name="locale">
<locale language="English" country="UnitedKingdom"/>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<layout class="QVBoxLayout" name="verticalLayout_bottom_left"/>
</item>
<item row="2" column="1">
<layout class="QVBoxLayout" name="verticalLayout_bottom_right"/>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_top_left"/>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_top_right"/>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="clear_button">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="color_button">
<property name="text">
<string>New random color</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>