Python tutorial bug with PyQt6 canvas

I’m following an online PyQt tutorial and the last example fails to run. I can see why, but don’t know how to fix it. It looks like the instantiation of the Canvas fails to create the canvas, because the “canvas” variable isn’t assigned anything.

It’s the last example (in three separate code blocks) on this page:
https://www.pythonguis.com/tutorials/pyq…-graphics/

#!/bin/python3
     
import sys
from PyQt6 import QtCore, QtGui, QtWidgets, uic
from PyQt6.QtCore import Qt
     
class Canvas(QtWidgets.QLabel):
    def __init__(self):
        super().__init__()
        pixmap = QtGui.QPixmap(600, 300)
        pixmap.fill(Qt.GlobalColor.white)
        self.setPixmap(canvas)
     
        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.label.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.label.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
     
     
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 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()

An earlier example has:

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()

        self.label = QtWidgets.QLabel()
        canvas = QtGui.QPixmap(400, 300)
        canvas.fill(Qt.GlobalColor.white)
        self.label.setPixmap(canvas)
        self.setCentralWidget(self.label)

        self.last_x, self.last_y = None, None

where it’s creating a QPixmap and subsequently passing it to setPixmap, so maybe your code should be doing the same thing:

class Canvas(QtWidgets.QLabel):
    def __init__(self):
        super().__init__()
        pixmap = QtGui.QPixmap(600, 300)
        pixmap.fill(Qt.GlobalColor.white)
        self.setPixmap(pixmap)

I don’t use Qt, so it’s untested.

Thanks for the help, Matthew.