[英]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.