2025, Dec 12 05:00

Fixing PyQt6 QPainter warnings on Windows (Qt 6.9): why they appear, how to silence them, and safer versions

Seeing QPainter 'Painter not active' spam in PyQt6 on Windows from the terminal? It's QTBUG-135844 in Qt 6.9; fixes land in 6.9.2. Use 6.8.x meanwhile.

PyQt6 applications that paint in QWidget can emit a burst of QPainter warnings on Windows when run from a terminal, but not when launched from PyCharm. The messages look like “QPainter::begin: Paint device returned engine == 0, type: 3” followed by a series of “Painter not active” lines. With PyQt6 built against the Qt 6.9 branch these warnings appear; with 6.8.x they do not. The code itself can be minimal and correct, yet the console still fills with QPainter output after a manual resize or when the window is snapped.

Reproducible minimal example

import sys
from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QWidget,
    QVBoxLayout,
    QLabel,
)
from PyQt6.QtGui import QPainter, QColor
from PyQt6.QtCore import Qt


class CanvasPane(QWidget):
    def __init__(self):
        print('----CanvasPane ctor enter')
        super().__init__()
        self.build_ui()
        print('----CanvasPane ctor leave')

    def build_ui(self):
        print('----CanvasPane UI enter')
        self.setGeometry(100, 100, 300, 200)
        column = QVBoxLayout()
        self.setLayout(column)
        caption = QLabel("This is a simple Qt application  ")
        column.addWidget(caption)
        print('----CanvasPane UI leave')

    def paintEvent(self, ev):
        print('----CanvasPane paint enter')
        pen = QPainter(self)
        pen.setPen(Qt.GlobalColor.blue)
        pen.drawLine(0, 0, 200, 100)
        print('----CanvasPane paint leave')


class AppShell(QMainWindow):
    def __init__(self):
        print('--AppShell ctor enter')
        super().__init__()
        self.setup_view()
        print('--AppShell ctor leave')

    def setup_view(self):
        print('--AppShell UI enter')
        self.setWindowTitle("Simple Qt Example  ")
        self.setGeometry(100, 100, 600, 400)
        pane = CanvasPane()
        self.setCentralWidget(pane)
        print('--AppShell UI leave')


if __name__ == "__main__":
    print('Boot application  ')
    qtapp = QApplication([])
    print('Create main window  ')
    main_win = AppShell()
    print('Show main window  ')
    main_win.show()
    print('Execute event loop  ')
    sys.exit(qtapp.exec())

What is actually happening

The warnings are triggered by a bug in the Qt 6.9 line, reported as QTBUG-135844. According to the public report, it has been addressed and is planned to ship with Qt 6.9.2, which is planned for mid‑August 2025. The code above is fine; the spurious QPainter messages are not caused by misuse of QPainter in the paintEvent and are reproducible with a trivial widget that draws a single line.

The discrepancy between running from a Windows terminal and from PyCharm is expected. PyCharm typically displays only what comes from the Python interpreter. PyQt is a binding over a C++ library, and those QPainter lines are native Qt warnings written outside Python’s stderr handling. They occur in both environments, but you only see them in places that capture native output. IDEs can sometimes be configured to show such external messages, but the safest habit is to test GUI programs from a plain terminal as well.

Resolution and practical guidance

If the warnings do not translate into functional problems for your application, you can continue working with your current setup and wait for the official 6.9.2 release. If they are disruptive, switch to a version that does not exhibit the problem. The report indicates the bug is specific to the 6.9 branch; the prior 6.8.3 release should theoretically be unaffected, as are earlier 6.8.x versions, provided they meet your project’s needs. Keep in mind that PyQt versioning does not always match Qt’s patch numbers one-to-one; the third component in PyQt’s version may reflect PyQt’s own patching rather than a Qt patch level.

There is no code change required for the minimal example above. The painter usage pattern in the paintEvent is correct: instantiating QPainter with the widget automatically begins painting, setting a pen, and drawing a primitive is valid. The warnings stem from the underlying Qt bug, not from application logic.

A side note that helps avoid real crashes in unrelated contexts: event handlers in Qt must be passed a proper QEvent instance of the right type. Manually invoking handlers such as resizeEvent with None is incorrect and may crash for widgets that implement those handlers.

Why this matters for day‑to‑day development

Native-library warnings that bypass Python can hide in IDE sessions and only surface in terminal runs. That mismatch complicates diagnosis and can mislead you into searching for problems in your code. Recognizing when the source is upstream—Qt in this case—saves time, helps you choose the right workaround, and prevents unnecessary refactoring. It also underscores the importance of version pinning and running smoke tests outside the IDE.

Conclusion

If you see QPainter “Painter not active” output with PyQt6 on Windows only when using the console and you are on the Qt 6.9 line, you are likely hitting QTBUG-135844. Either tolerate the warnings until the planned 6.9.2 release or temporarily use a 6.8.x build that fits your requirements. Keep an eye on the public bug report for updates, run GUI tests from a terminal in addition to the IDE, avoid manual invocation of event handlers, and be cautious about adopting brand‑new minor versions unless you need them right away. The minimal code above is sound; the noise is upstream and transient.