这是我编写的应用程序的简化。
应用程序的主窗口有一个按钮和一个复选框。 该复选框位于QScrollArea内(通过小部件)。 该复选框有一个数字,表明该复选框的创建次数。 单击该按钮将打开一个带有刷新按钮的对话框。
单击刷新按钮将使用新复选框将新窗口小部件设置到滚动区域。
该复选框有一个上下文菜单,可以打开相同的对话框。 但是,当使用复选框的上下文菜单触发的对话框创建窗口小部件时,应用程序崩溃并出现以下错误:
2016-08-03 09:22:00.036 Python [17690:408202] modalSession已经发布 提前退出 - 检查对endModalSession的重新调用:
Python(17690,0x7fff76dcb300)malloc: *对象的错误 0x7fff5fbfe2c0:未分配被释放的指针 * 在malloc_error_break中设置断点以进行调试
单击按钮打开对话框并单击对话框中的刷新时,不会发生崩溃。
崩溃发生在Mac和Windows上。 我使用Python 2.7.10和PySide 1.2.4
#!/usr/bin/env python
import sys
from itertools import count
from PySide import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.centralwidget = QtGui.QWidget(parent=self)
self.open_diag_btn = QtGui.QPushButton('Open dialog', parent=self)
self.open_diag_btn.clicked.connect(self.open_dialog)
self.scroll_widget = QtGui.QScrollArea(parent=self)
layout = QtGui.QGridLayout(self.centralwidget)
layout.addWidget(self.scroll_widget)
layout.addWidget(self.open_diag_btn)
self.setCentralWidget(self.centralwidget)
self.set_scroll_widget()
def open_dialog(self):
dialog = Dialog(parent=self)
dialog.refresh.connect(self.set_scroll_widget) # Connecting the signal from the dialog to set a new widget to the scroll area
dialog.exec_()
# Even if I call the function here, after the dialog was closed instead of using the signal above the application crashes, but only via the checkbox
# self.set_scroll_widget()
def set_scroll_widget(self):
"""Replacing the widget of the scroll area with a new one.
The checkbox in the layout of the widget has an class instance counter so you can see how many times the checkbox was created."""
widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout(widget)
widget.setLayout(layout)
open_diag_check = RefreshCheckbox(parent=self)
open_diag_check.do_open_dialog.connect(self.open_dialog) # Connecting the signal to open the dialog window
layout.addWidget(open_diag_check)
self.scroll_widget.setWidget(widget)
class RefreshCheckbox(QtGui.QCheckBox):
"""A checkbox class that has a context menu item which emits a signal that eventually opens a dialog window"""
do_open_dialog = QtCore.Signal()
_instance_counter = count(1)
def __init__(self, *args, **kwargs):
super(RefreshCheckbox, self).__init__(unicode(self._instance_counter.next()), *args, **kwargs)
self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
action = QtGui.QAction(self)
action.setText("Open dialog")
action.triggered.connect(self.emit_open_dialog)
self.addAction(action)
def emit_open_dialog(self):
self.do_open_dialog.emit()
class Dialog(QtGui.QDialog):
"""A dialog window with a button that emits a refresh signal when clicked.
This signal is used to call MainWindow.set_scroll_widget()"""
refresh = QtCore.Signal()
def __init__(self, *args, **kwargs):
super(Dialog, self).__init__(*args, **kwargs)
self.refresh_btn = QtGui.QPushButton('Refresh')
self.refresh_btn.clicked.connect(self.do_refresh)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.refresh_btn)
def do_refresh(self):
self.refresh.emit()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
mySW = MainWindow()
mySW.show()
mySW.raise_()
app.exec_()
答案 0 :(得分:1)
看起来Python正试图删除一个不再存在的对象(或其中一个子对象) - 但是导致这种情况发生的原因并不完全清楚。有问题的对象是滚动区域上设置的小部件。如果你明确地提到它:
def set_scroll_widget(self):
self._old_widget = self.scroll_widget.takeWidget()
...
您的示例将不再转储核心。
我认为运行带有exec
的对话框可能会以某种方式成为问题的近因,因为这意味着它将使用自己的事件循环运行(这可能会影响与删除相关的事件的顺序)。通过使用show
:
def open_dialog(self):
dialog = Dialog(parent=self)
dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
dialog.refresh.connect(self.set_scroll_widget)
dialog.setModal(True)
dialog.show()
这样做意味着不再需要保持对前一个滚动区域小部件的显式引用。