当我关闭具有记录器的窗口然后重新打开该窗口时,我收到“RuntimeError:内部 C++ 对象 (PySide6.QtWidgets.QPlainTextEdit) 已删除。”(我根据这篇文章制作了记录器: 在 pyqt 中显示日志的最佳方式? )。 当我从 LoggerWindow 的 closeEvent 中删除“self.deleteLater()”时,我没有收到错误,因为 QWidget 未被删除。但问题是,在我的程序中,我需要“self.deleteLater()”来检测窗口是否已关闭(使用 self.(QWidget).destroyed.connect())。 有什么方法可以避免此错误,或者是否有不同的方法来检测窗口何时关闭?
from PySide6.QtWidgets import QApplication, QWidget, QPlainTextEdit, QVBoxLayout, QPushButton
import os
import logging
import sys
class QTextEditLogger(logging.Handler):
def __init__(self, parent):
super().__init__()
self.widget = QPlainTextEdit(parent)
self.widget.setReadOnly(True)
def emit(self, record):
msg = self.format(record)
self.widget.appendPlainText(msg)
class LoggerWindow(QWidget):
parent_dir = os.getcwd()
def __init__(self):
super().__init__()
self.logger_text_edit = QTextEditLogger(self)
self.logger_text_edit.setFormatter(logging.Formatter('[%(asctime)s %(levelname)s]: %(message)s'))
logging.getLogger().addHandler(self.logger_text_edit)
logging.getLogger().setLevel(logging.DEBUG)
logging.info("Initialized")
main_v_layout = QVBoxLayout()
main_v_layout.addWidget(self.logger_text_edit.widget)
self.setLayout(main_v_layout)
def closeEvent(self, event):
self.deleteLater()
class MainWindow(QWidget):
def __init__(self, app):
super().__init__()
main_v_layout = QVBoxLayout()
button = QPushButton("Push!")
main_v_layout.addWidget(button)
self.setLayout(main_v_layout)
button.clicked.connect(self.button_clicked)
def button_clicked(self):
self.logger_window = LoggerWindow()
self.logger_window.show()
app = QApplication(sys.argv)
window = MainWindow(app)
window.show()
app.exec()
这个错误的发生是因为你在
LoggerWindow
中的
__init__
方法中将
QTextEditLogger
实例化并将它添加为 logger 的 handler。当
LoggerWindow
被删除时,
QTextEditLogger
也被删除,包括它的
QPlainTextEdit
widget。
后来,当 logger 试图写入到
QTextEditLogger
时,
QTextEditLogger
已经不存在了,它的
QPlainTextEdit
也被删除了,所以会发生“内部 C++ 对象已删除”的错误。
为了解决这个问题,你可以在
LoggerWindow
被删除时移除
QTextEditLogger
作为 logger 的 handler:
class LoggerWindow(QWidget):
...
def closeEvent(self, event):
logging.getLogger().removeHandler(self.logger_text_edit)
self.deleteLater()
这样做可以确保在
QTextEditLogger
被删除之前,logger 不再尝试使用它。
另外,你也可以使用 Qt 的信号和槽机制来检测窗口何时关闭,而不是依赖
self.deleteLater()
和
destroyed
信号:
class LoggerWindow(QWidget):
...
def closeEvent(self, event):
logging.getLogger().removeHandler(self.logger_text_edit)
# 发出窗口关闭的信号
self.close_signal.emit()
event.accept()
def __init__(self):
...
# 创建 close_signal 信号
self.close_signal = Signal()
class MainWindow(QWidget):
...
def button_clicked(self):
self.logger_window = LoggerWindow()
self.logger_window.show()
# 连接 close_signal 信号到槽函数
self.logger_window.close_signal.connect(self.on_logger_window_closed)
def on_logger_window_closed(self):
# 在这里处理 logger 窗口关闭的逻辑
print("Logger window closed!")
这样,当
LoggerWindow
关闭时,
close_signal
信号会被发射,
MainWindow
中的
on_logger_window_closed
槽函数会被调用,你可以在该函数中处理窗口关闭的逻辑。