我有一个Treeview
(继承自QTreeView
)模型QFileSystemModel
。这个Treeview
对象被添加到另一个带有QPushButton
. 该按钮将通过 a 打开一个目录QFileDialog
,并调用Treeview
的set_directory
方法。该方法将模型的根路径设置为所选目录,并将修改树视图的根索引。然后选择树视图中最顶部的项目。
但是,第一次选择目录时,不会选择最顶部的项目。注释掉第 11 行:self.model.directoryLoaded.connect(self.set_directory)
,解决了问题。但这意味着该set_directory
方法被调用两次:
# default directory opened
<class 'NoneType'>
# open new directory, set_directory called twice
<class 'NoneType'>
<class 'PyQt5.QtWidgets.QFileSystemModel'>
如命令行输出所示,该QModelIndex.model()
方法在第一次选择目录时返回 NoneType。如何在不调用该set_directory
方法两次的情况下将树视图的当前索引设置为最顶部的项目?QModelIndex
当目录未被访问时,为什么模型是 NoneType ?
主要脚本如下:
from PyQt5.QtWidgets import QPushButton, QTreeView, QFileSystemModel, QWidget, QFileDialog, QApplication, QHBoxLayout
import sys
class Treeview(QTreeView):
def __init__(self, parent=None):
super(QTreeView, self).__init__(parent)
self.model = QFileSystemModel()
self.setModel(self.model)
self.set_directory(".")
# self.model.directoryLoaded.connect(self.set_directory)
def set_directory(self, path):
self.setRootIndex(self.model.setRootPath(path))
self.setCurrentIndex(self.model.index(0, 0, self.rootIndex()))
print(type(self.model.index(0, 0, self.rootIndex()).model()))
class MainWidget(QWidget):
def __init__(self, parent=None):
super(QWidget, self).__init__(parent)
self.tview = Treeview(self)
vlayout = QHBoxLayout(self)
vlayout.addWidget(self.tview)
open_button = QPushButton(self)
open_button.clicked.connect(self.open_dir)
vlayout.addWidget(open_button)
def open_dir(self):
filepath = QFileDialog.getExistingDirectory(self)
if filepath:
self.tview.set_directory(filepath)
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MainWidget()
widget.show()
sys.exit(app.exec_())
存在三个问题:
directoryLoaded
每当第一次加载目录的内容时调用,这在单独的线程上异步发生;如果“根”目录的内容还没有被加载,它就没有子目录,所以任何访问根索引子目录的尝试都将返回无效索引(这就是你得到的原因None
);set_directory
:如果您打开文件夹“home”然后展开目录“documents”,模型将加载所有它的内容并directoryLoaded
为“文档”文件夹发出,然后set_directory
将再次依次调用;考虑到上述情况,您不能依赖directoryLoaded
(当然您不应该将它连接到set_directory
),但是您可以使用该layoutChanged
信号,因为它总是在排序完成时发出(并且 QFileSystemModel 总是在根更改时对模型进行排序);唯一的问题是您必须仅在需要时才这样做。
解决方案是创建一个函数来尝试设置顶部项目,如果它无效,则它将自身连接到layoutChanged
信号;此时,当模型完成其工作并且顶部索引可用时,将发出信号。使用标志可以帮助我们知道信号是否已连接,然后断开它,这在您需要支持排序的情况下很重要。
class Treeview(QTreeView):
layoutCheck = False
def __init__(self, parent=None):
super(QTreeView, self).__init__(parent)
self.model = QFileSystemModel()
self.setModel(self.model)
self.set_directory(QDir.currentPath())
self.setSortingEnabled(True)
def setTopIndex(self):
topIndex = self.model.index(0, 0, self.rootIndex())
print(topIndex.isValid(), topIndex.model())
if topIndex.isValid():
self.setCurrentIndex(topIndex)
if self.layoutCheck:
self.model.layoutChanged.disconnect(self.setTopIndex)
self.layoutCheck = False
else:
if not self.layoutCheck:
self.model.layoutChanged.connect(self.setTopIndex)
self.layoutCheck = True
def set_directory(self, path):
self.setRootIndex(self.model.setRootPath(path))
self.setTopIndex()
请考虑layoutCheck
标志非常重要,原因有很多:
layoutChanged
是始终在型号排序射出; 这不仅在尝试使用标题进行排序时发生,而且在添加文件或目录时也会发生;一种可能性是使用Qt.UniqueConnection
连接类型和一个try
块来断开连接,但是,虽然这种方法有效并且是一致的,但它有点麻烦:只要连接始终与设置配对,使用基本的布尔标志要简单得多并且更容易阅读和理解。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句