PySide2中backend_qt报错:self.window().windowHandle()返回None求助
PySide2嵌入Matplotlib图表时backend_qt报错导致窗口崩溃的问题
问题描述
使用Python 3.8.10(无法自主选择版本)结合PySide2开发GUI窗口,嵌入matplotlib图表时,backend_qt包出现报错。示例代码中该问题影响不大,但集成到完整项目后会导致窗口崩溃或显示异常。报错在窗口打开和关闭时各出现一次,根源是self.window().windowHandle()返回了None,但不清楚原因。
示例代码
import sys from matplotlib import pyplot as plt from PySide2.QtWidgets import (QHBoxLayout, QWidget, QApplication) from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg class MplCanvas(FigureCanvasQTAgg): # Create canavs to display graph def __init__(self, parent, width=15, height=4, dpi=100): fig, self.axis = plt.subplots(figsize=(width, height), dpi=dpi) super().__init__(fig) self.setParent(parent) self.window = FigureCanvasQTAgg class OutputWindow(QWidget): def __init__(self): super().__init__() self.chart = MplCanvas(self) self.create_params_box() def create_params_box(self): self.hbox = QHBoxLayout() self.hbox.addWidget(self.chart) app = QApplication(sys.argv) demo = OutputWindow() demo.setLayout(demo.hbox) demo.showMaximized() sys.exit(app.exec_())
报错信息
Traceback (most recent call last): File "~\venv\lib\site-packages\matplotlib\backends\backend_qt.py", line 276, in showEvent window.screenChanged.connect(self._update_screen) AttributeError: 'NoneType' object has no attribute 'screenChanged'
backend_qt中的相关代码
def showEvent(self, event): window = self.window().windowHandle() window.screenChanged.connect(self._update_screen) self._update_screen(window.screen())
已尝试操作
- 将原始代码精简为示例代码
- 更换PySide2版本至5.15.2、5.15.1、5.14.x
- 示例代码可正常运行,但集成到完整项目时窗口崩溃
解决方案
1. 修复MplCanvas错误赋值并增加空值判断
原代码中self.window = FigureCanvasQTAgg是错误赋值,会覆盖Qt的window()方法,这是引发问题的关键原因之一。同时重写showEvent方法增加空值判断:
import sys from matplotlib import pyplot as plt from PySide2.QtWidgets import (QHBoxLayout, QWidget, QApplication) from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg class MplCanvas(FigureCanvasQTAgg): def __init__(self, parent, width=15, height=4, dpi=100): fig, self.axis = plt.subplots(figsize=(width, height), dpi=dpi) super().__init__(fig) self.setParent(parent) # 移除错误的self.window赋值 def showEvent(self, event): window = self.window().windowHandle() if window is not None: window.screenChanged.connect(self._update_screen) self._update_screen(window.screen()) super().showEvent(event) class OutputWindow(QWidget): def __init__(self): super().__init__() self.chart = MplCanvas(self) self.create_params_box() self.setLayout(self.hbox) # 提前设置布局,避免时机问题 def create_params_box(self): self.hbox = QHBoxLayout() self.hbox.addWidget(self.chart) app = QApplication(sys.argv) demo = OutputWindow() demo.showMaximized() sys.exit(app.exec_())
2. 延迟初始化画布确保窗口完全创建
在窗口的showEvent中初始化图表,保证窗口句柄已生成:
import sys from matplotlib import pyplot as plt from PySide2.QtWidgets import (QHBoxLayout, QWidget, QApplication) from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg class MplCanvas(FigureCanvasQTAgg): def __init__(self, parent, width=15, height=4, dpi=100): fig, self.axis = plt.subplots(figsize=(width, height), dpi=dpi) super().__init__(fig) self.setParent(parent) class OutputWindow(QWidget): def __init__(self): super().__init__() self.chart = None self.create_params_box() self.setLayout(self.hbox) def create_params_box(self): self.hbox = QHBoxLayout() def showEvent(self, event): if self.chart is None: self.chart = MplCanvas(self) self.hbox.addWidget(self.chart) super().showEvent(event) app = QApplication(sys.argv) demo = OutputWindow() demo.showMaximized() sys.exit(app.exec_())
3. 避免使用pyplot全局状态,直接创建Figure对象
减少pyplot全局状态带来的潜在冲突:
import sys from matplotlib.figure import Figure from PySide2.QtWidgets import (QHBoxLayout, QWidget, QApplication) from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg class MplCanvas(FigureCanvasQTAgg): def __init__(self, parent, width=15, height=4, dpi=100): fig = Figure(figsize=(width, height), dpi=dpi) self.axis = fig.add_subplot(111) super().__init__(fig) self.setParent(parent) def showEvent(self, event): window = self.window().windowHandle() if window is not None: window.screenChanged.connect(self._update_screen) self._update_screen(window.screen()) super().showEvent(event) class OutputWindow(QWidget): def __init__(self): super().__init__() self.chart = MplCanvas(self) self.create_params_box() self.setLayout(self.hbox) def create_params_box(self): self.hbox = QHBoxLayout() self.hbox.addWidget(self.chart) app = QApplication(sys.argv) demo = OutputWindow() demo.showMaximized() sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者jtparm2
相关产品推荐
相关产品推荐

