On the page " QPainter and Bitmap Graphics in PySide6" we can read: "When we only have a single widget in the window this is fine — as long as you don’t resize the window larger than the widget (did you try that?), the coordinates of the container and the single nested widget line up. However, if we add other widgets to the layout this won’t hold — the coordinates of the QLabel
will be offset from the window, and we’ll be drawing in the wrong location.
This is easily fixed by moving the mouse handling onto the QLabel
itself— it’s event coordinates are always relative to itself."
Despite that change, resizing the main window still breaks coordinates for drawing. I tried to look up solutions in the documentation, but it’s unintelligible. To be clear, I was checking it on the code provided by the course:
import sys
from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtCore import Qt
COLORS = [
# 17 undertones https://lospec.com/palette-list/17undertones
'#000000', '#141923', '#414168', '#3a7fa7', '#35e3e3', '#8fd970', '#5ebb49',
'#458352', '#dcd37b', '#fffee5', '#ffd035', '#cc9245', '#a15c3e', '#a42f3b',
'#f45b7a', '#c24998', '#81588d', '#bcb0c2', '#ffffff',
]
class QPaletteButton(QtWidgets.QPushButton):
def __init__(self, color):
super().__init__()
self.setFixedSize(QtCore.QSize(24,24))
self.color = color
self.setStyleSheet("background-color: %s;" % color)
class Canvas(QtWidgets.QLabel):
def __init__(self):
super().__init__()
pixmap = QtGui.QPixmap(600, 300)
# pixmap = QtGui.QPixmap(self.width(), self.height())
pixmap.fill(Qt.white)
self.setPixmap(pixmap)
self.last_x, self.last_y = None, None
self.pen_color = QtGui.QColor('#000000')
def set_pen_color(self, c):
self.pen_color = QtGui.QColor(c)
def mouseMoveEvent(self, e):
if self.last_x is None: # First event.
self.last_x = e.position().x()
self.last_y = e.position().y()
return # Ignore the first time.
canvas = self.pixmap()
painter = QtGui.QPainter(canvas)
p = painter.pen()
p.setWidth(4)
p.setColor(self.pen_color)
painter.setPen(p)
painter.drawLine(self.last_x, self.last_y, e.position().x(), e.position().y())
painter.end()
self.setPixmap(canvas)
# Update the origin for next time.
self.last_x = e.position().x()
self.last_y = e.position().y()
def mouseReleaseEvent(self, e):
self.last_x = None
self.last_y = None
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.canvas = Canvas()
w = QtWidgets.QWidget()
l = QtWidgets.QVBoxLayout()
w.setLayout(l)
l.addWidget(self.canvas)
palette = QtWidgets.QHBoxLayout()
self.add_palette_buttons(palette)
l.addLayout(palette)
self.setCentralWidget(w)
def add_palette_buttons(self, layout):
for c in COLORS:
b = QPaletteButton(c)
b.pressed.connect(lambda c=c: self.canvas.set_pen_color(c))
layout.addWidget(b)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()