[英]Crash when combining QFileSystemModel with QSortFilterProxyModel
[英]PyQt5 Crash with QFileSystemModel and QSortFilterProxyModel..doing something wrong?
在Ubuntu上使用pyqt5导航目录结构时,出现了间歇性的崩溃问题。 有时,仅浏览到一个文件夹会崩溃,而其他时候,它是由对所显示目录的外部更改触发的。 以下代码是后者的示例。
我正在构建的应用程序会在激活程序时检查正在显示的目录。 如果它不再是有效目录,它将在树中上移到下一个有效目录。 下面的代码通过创建目录结构,导航到文件并选择它,重命名树,然后从不再有效的目录移动到该目录,来模拟这种情况。 如果我多次运行此代码,有时会在第一次执行时,有时在几次运行后会崩溃。
我尝试根据在gdb堆栈跟踪中看到的代理模型功能来更新模式。 这似乎解决了我的问题,尽管这对我来说似乎是错误的。
尽管我对解决方案不满意,但我已将其固定修复,但是今天即使进行了模型更新,我也再次在代码中崩溃。
那里没有很多示例代码显示如何一起使用这些类。 有人看到我在做什么错吗?
import os, sys, tempfile
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
layout = QtWidgets.QVBoxLayout()
self.setLayout(layout)
self._view = QtWidgets.QTableView()
layout.addWidget(self._view)
self._model = QtWidgets.QFileSystemModel()
self._model.setFilter(QtCore.QDir.AllDirs | QtCore.QDir.AllEntries)
self._proxy = QtCore.QSortFilterProxyModel(self)
self._proxy.setSourceModel(self._model)
self._view.setModel(self._proxy)
header = self._view.horizontalHeader()
header.setSortIndicator(0, QtCore.Qt.AscendingOrder)
self._proxy.sort(header.sortIndicatorSection(), header.sortIndicatorOrder())
# Create a temporary directory structure (tmpxyz/a/b/c) starting at the location of this file
# This is oddly very specific..less nesting or no file to select doesn't exhibit the problem!?
path = os.path.dirname(os.path.abspath(__file__))
self.temp_dir = tempfile.TemporaryDirectory(dir=path)
print('created temporary directory', self.temp_dir.name)
foo_dir = os.path.join(self.temp_dir.name, 'foo')
os.mkdir(foo_dir)
self.a_dir = os.path.join(foo_dir, 'a')
os.mkdir(self.a_dir)
b_dir = os.path.join(self.a_dir, 'b')
os.mkdir(b_dir)
c_dir = os.path.join(b_dir, 'c')
os.mkdir(c_dir)
self.temp_file_name = os.path.join(c_dir, 'foo.txt')
with open(self.temp_file_name, 'w') as txtfile:
print('foo', file=txtfile)
self._model.setRootPath(c_dir)
# moved the following to loaded..didn't seem to help
# source_index = self._model.index(c_dir)
# index = self._proxy.mapFromSource(source_index)
# self._view.setRootIndex(index)
QtCore.QTimer.singleShot(4000, self._select_temp_file)
QtCore.QTimer.singleShot(5000, self._rename_test_dir)
self._model.directoryLoaded.connect(self._loaded)
def _loaded(self):
print('_loaded')
path = self._model.rootPath()
print('_loaded', path)
source_index = self._model.index(path)
index = self._proxy.mapFromSource(source_index)
self._view.setRootIndex(index)
def _select_temp_file(self):
source_index = self._model.index(self.temp_file_name)
if source_index.isValid():
index = self._proxy.mapFromSource(source_index)
self._view.setCurrentIndex(index)
# Simulate an external application moving the current directory
def _rename_test_dir(self):
os.rename(self.a_dir, self.a_dir+'x')
path = self._model.rootPath()
print('_rename_test_dir', path)
if not os.path.isdir(path):
def _make_valid_path(path_):
if os.path.isdir(path_):
return path_
while path_:
path_, _ = os.path.split(path_)
if os.path.isdir(path_):
return path_
return '/'
print('Path not valid:', path)
path = _make_valid_path(path)
print('New Path:', path)
self._model.setRootPath(path)
print('_rename_test_dir 5')
# Using gdb showed a crash in the proxy model..so update it here...decreases crash frequency
# self._proxy.setSourceModel(self._model)
# print('_rename_test_dir 6')
# self._view.setModel(self._proxy)
print('_rename_test_dir 7')
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
widget = Widget()
widget.show()
sys.exit(app.exec_())
更新:
如果代码中不清楚,则该程序不需要交互,并且交互会干扰测试。 创建目录结构后,它将自动进入结构的叶级。 4秒钟后,它将选择foo.txt文件。 再过一秒钟,它将在树中重命名“ a”目录,然后在树上导航回到“ a”所在的位置。 如果一切顺利,将显示foo目录,从中可以看到'ax'目录,并且可以退出和重试该程序。
在获取以下堆栈跟踪之前,在gbd下执行了大约8次。编辑为最后2次运行:
gdb --args python3 test_qfilesystemmodel_crash2.py
(gdb) run
Starting program: /usr/bin/python3 test_qfilesystemmodel_crash2.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffe9ea5700 (LWP 21128)]
[New Thread 0x7fffdb5e5700 (LWP 21129)]
[New Thread 0x7fffdade4700 (LWP 21130)]
created temporary directory /home/myuser/Desktop/haiqu/src/tmp8dl0_uny
_loaded
_loaded /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo/a/b/c
_rename_test_dir /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo/a/b/c
Path not valid: /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo/a/b/c
New Path: /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo
_rename_test_dir 5
_rename_test_dir 7
_loaded
_loaded /home/myuser/Desktop/haiqu/src/tmp8dl0_uny/foo
[Thread 0x7fffdb5e5700 (LWP 21129) exited]
[Thread 0x7fffe9ea5700 (LWP 21128) exited]
[Thread 0x7ffff7fbb700 (LWP 21127) exited]
[Inferior 1 (process 21127) exited normally]
(gdb) run
Starting program: /usr/bin/python3 test_qfilesystemmodel_crash2.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffe9ea5700 (LWP 21132)]
[New Thread 0x7fffdb5e5700 (LWP 21133)]
[New Thread 0x7fffdade4700 (LWP 21134)]
created temporary directory /home/myuser/Desktop/haiqu/src/tmpwr560n5l
_loaded
_loaded /home/myuser/Desktop/haiqu/src/tmpwr560n5l/foo/a/b/c
_rename_test_dir /home/myuser/Desktop/haiqu/src/tmpwr560n5l/foo/a/b/c
Path not valid: /home/myuser/Desktop/haiqu/src/tmpwr560n5l/foo/a/b/c
New Path: /home/myuser/Desktop/haiqu/src/tmpwr560n5l/foo
_rename_test_dir 5
_rename_test_dir 7
Thread 1 "python3" received signal SIGSEGV, Segmentation fault.
0x00007ffff5062e89 in QSortFilterProxyModel::sibling(int, int, QModelIndex const&) const ()
from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
(gdb) bt
#0 0x00007ffff5062e89 in QSortFilterProxyModel::sibling(int, int, QModelIndex const&) const ()
from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#1 0x00007ffff568d2d4 in ?? () from /usr/lib/python3/dist-packages/PyQt5/QtCore.cpython-35m-x86_64-linux-gnu.so
#2 0x00007ffff0af35ff in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#3 0x00007ffff00f9779 in QAccessible::updateAccessibility(QAccessibleEvent*) ()
from /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5
#4 0x00007ffff0b028cc in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#5 0x00007ffff0b07486 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#6 0x00007ffff50cb4a9 in QMetaObject::activate(QObject*, int, int, void**) ()
from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#7 0x00007ffff51426e4 in QAbstractItemModel::rowsInserted(QModelIndex const&, int, int, QAbstractItemModel::QPrivateSignal) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#8 0x00007ffff5046f7b in QAbstractItemModel::endInsertRows() () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#9 0x00007ffff5068246 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#10 0x00007ffff506a685 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#11 0x00007ffff506e089 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#12 0x00007ffff50cb4a9 in QMetaObject::activate(QObject*, int, int, void**) ()
from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#13 0x00007ffff51426e4 in QAbstractItemModel::rowsInserted(QModelIndex const&, int, int, QAbstractItemModel::QPrivateSignal) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#14 0x00007ffff5046f7b in QAbstractItemModel::endInsertRows() () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#15 0x00007ffff0acf6e6 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#16 0x00007ffff0ad51f9 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#17 0x00007ffff50cc359 in QObject::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#18 0x00007ffff0ad58b2 in QFileSystemModel::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#19 0x00007ffff131ecdb in ?? () from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-35m-x86_64-linux-gnu.so
#20 0x00007ffff08b635c in QApplicationPrivate::notify_helper(QObject*, QEvent*) ()
from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#21 0x00007ffff08bdb11 in QApplication::notify(QObject*, QEvent*) ()
from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#22 0x00007ffff124cdee in ?? () from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-35m-x86_64-linux-gnu.so
#23 0x00007ffff509f8a0 in QCoreApplication::notifyInternal2(QObject*, QEvent*) ()
from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#24 0x00007ffff50a202d in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) ()
from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#25 0x00007ffff50f3b03 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#26 0x00007ffff3b35377 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#27 0x00007ffff3b355e0 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#28 0x00007ffff3b3568c in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#29 0x00007ffff50f3f0f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) ()
from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#30 0x00007ffff509d88a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) ()
from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#31 0x00007ffff50a5ffc in QCoreApplication::exec() () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#32 0x00007ffff1210ddb in ?? () from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-35m-x86_64-linux-gnu.so
#33 0x000055555571b28f in PyCFunction_Call ()
#34 0x00005555556d21e9 in PyEval_EvalFrameEx ()
#35 0x00005555556d6d16 in ?? ()
#36 0x00005555556d7a1f in PyEval_EvalCode ()
#37 0x00005555557a4b02 in ?? ()
#38 0x00005555557a6f8d in PyRun_FileExFlags ()
#39 0x00005555557a772e in PyRun_SimpleFileExFlags ()
#40 0x00005555557d72e7 in Py_Main ()
#41 0x0000555555667b31 in main ()
(gdb)
我把它写成一个旧的图书馆问题。 更新到pyqt5.8和python3.6后,我不再能够重现崩溃。 谢谢您的帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.