2026, Jan 01 12:01
QPainter «Painter not active» в PyQt6 на Windows: причина в Qt 6.9 и что делать
Почему в PyQt6 на Windows появляются предупреждения QPainter в Qt 6.9 (QTBUG-135844) и как их обойти: дождаться 6.9.2 или временно использовать 6.8.x; код примера верен.
Приложения PyQt6, которые рисуют внутри QWidget, при запуске из терминала в Windows могут выдавать серию предупреждений QPainter, тогда как при запуске из PyCharm этого не видно. Сообщения выглядят так: «QPainter::begin: Paint device returned engine == 0, type: 3», а затем идут строки «Painter not active». В сборках PyQt6 на базе ветки Qt 6.9 эти предупреждения появляются; на 6.8.x — нет. Сам код может быть минимальным и корректным, но после ручного изменения размера или когда окно пристыковывают к краю экрана консоль всё равно заполняется выводом QPainter.
Воспроизводимый минимальный пример
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())
Что на самом деле происходит
Предупреждения вызываются ошибкой в линейке Qt 6.9, зарегистрированной как QTBUG-135844. Согласно публичному отчёту, проблему исправили, и исправление планируется включить в Qt 6.9.2, релиз которой намечен на середину августа 2025 года. Приведённый выше код в порядке; ложные сообщения QPainter не связаны с неправильным использованием QPainter в paintEvent и воспроизводятся на простейшем виджете, рисующем одну линию.
Разница между запуском из терминала Windows и из PyCharm ожидаема. PyCharm обычно показывает только то, что выводит интерпретатор Python. PyQt — это привязка к библиотеке на C++, а строки QPainter — это нативные предупреждения Qt, выводимые в обход обработчика stderr Python. Они возникают в обоих случаях, просто видите их там, где перехватывается нативный вывод. В IDE иногда можно включить показ таких сообщений, но надёжнее дополнительно проверять GUI‑приложения в обычном терминале.
Решение и практические рекомендации
Если предупреждения не выливаются в реальные проблемы для вашего приложения, можно продолжать работать с текущей конфигурацией и дождаться официального релиза 6.9.2. Если они мешают, переключитесь на версию, в которой проблема не проявляется. В отчёте сказано, что баг специфичен для ветки 6.9; предыдущий релиз 6.8.3 теоретически не затронут, как и более ранние версии 6.8.x — при условии, что они подходят под задачи проекта. Учтите, что версии PyQt не всегда один к одному совпадают с патч‑уровнем Qt: третий компонент версии PyQt может отражать собственные исправления PyQt, а не номер патча Qt.
Для минимального примера выше менять код не требуется. Паттерн работы с QPainter в paintEvent корректен: создание QPainter с виджетом автоматически инициирует рисование, установка пера и отрисовка примитива — валидные действия. Источник предупреждений — баг в Qt, а не логика приложения.
Небольшое примечание, чтобы избежать реальных падений в несвязанных ситуациях: обработчикам событий в Qt нужно передавать корректный экземпляр QEvent соответствующего типа. Ручной вызов обработчиков вроде resizeEvent с None неверен и может приводить к сбою для виджетов, где эти обработчики реализованы.
Почему это важно в повседневной разработке
Предупреждения из нативной библиотеки, обходящие Python, могут «прятаться» в сессиях IDE и проявляться только при запуске из терминала. Такая рассинхронизация усложняет диагностику и подталкивает искать проблему в собственном коде. Понимание, что источник — «выше по стеку» (в данном случае Qt), экономит время, помогает выбрать верный обходной путь и предотвращает лишние рефакторинги. Это также подчёркивает ценность фиксации версий и дымовых тестов вне IDE.
Итог
Если вы видите вывод QPainter «Painter not active» в PyQt6 на Windows только при работе через консоль и используете линейку Qt 6.9, скорее всего, вы упираетесь в QTBUG-135844. Либо терпите предупреждения до планируемого релиза 6.9.2, либо временно используйте сборку 6.8.x, которая вам подходит. Следите за обновлениями в публичном отчёте об ошибке, запускайте GUI‑тесты из терминала в дополнение к IDE, не вызывайте обработчики событий вручную и аккуратно переходите на новые минорные версии, только если они действительно нужны прямо сейчас. Минимальный код выше корректен; «шум» идёт с апстрима и носит временный характер.