pyqt4 QFileSystemModel 中的条件自定义行
Conditional custom rows in pyqt4 QFileSystemModel
我想在 QTreeview 下的 QFileSystemModel 中添加自定义行。仅当目录包含具有特定扩展名的文件时才添加该行。基本上,在启动目录列表后,用户将单击文件夹。一旦用户单击的文件夹包含目标文件,我想隐藏这些文件(我知道该怎么做),然后使用自定义行来表示这些文件的摘要。
例如,如果文件夹包含如下文件
A.01.dat
A.02.dat
A.03.dat
...
B.01.dat
B.02.dat
B.03.dat
我想创建自定义行:
A
B
但是,如果单击的文件夹不包含这些 .dat 文件,则不应创建自定义行。
我也尝试过将行直接插入到 QFileSystemModel
self.treeivew.model = QtGui.QFileSystemModel()
...
for n, s in enumerate(self.sequence):
self.treeview.model.beginInsertRows(index, 0, 0)
result = self.treeview.model.insertRow(1, index)
print(result)
self.treeview.model.setData(index, QString(s['Name']),role=QtCore.Qt.DisplayRole)
self.treeview.model.endInsertRows()
但是插入失败
如果需要重新实现,正如我在很多地方看到的那样,谁能提供一个 具体 示例,说明应该如何重新实现以允许这种有条件的自定义行插入?
提前致谢。
我会实现一个带有动态子项插入的项目模型。这只是一个标准 QAbstractItemModel
和一些额外的方法 -
- rowCount - 你通常会为树模型实现它。如果节点有尚未加载的子节点,请确保它 returns 0。
- hasChildren - 对于具有尚未加载的子节点的节点覆盖到 return
True
并且 return 无论基础 class returns 在所有其他情况下。
- canFetchMore - return
True
如果节点有尚未加载的子节点,False
否则。
- fetchMore - 在这里您可以执行您需要的任何逻辑来决定要创建哪些节点并将它们插入到模型中。
这是基本思路 - 对于您知道的节点有尚未加载的子节点,return 0 来自 rowCount
和 True
来自 canFetchMore
和 hasChildren
。这告诉 Qt 显示一个节点,旁边有一个扩展器,即使它当前没有子节点。单击扩展器时,将调用 fetchMore
并从给定的父级填充子级。
需要注意一件事 - 您必须在 fetchMore
方法中调用 beginInsertRows
和 endInsertRows
。此外,您不得在调用 beginInsertRows
之前或 endInsertRows
之后更改基础数据存储。不幸的是,您需要知道在调用 beginInsertRows
时要插入多少行 - 因此您可能想要生成要添加的节点列表,然后调用 beginInsertRows
。但是,如果您这样做,则无法设置新节点的父节点,因为它会更改底层数据存储。
您可以在下面的代码中看到,我在 Node.insert_child
方法中设置了父节点,该方法在 beginInsertRows
和 endInsertRows
调用之间调用。
该代码并不完全符合您的要求 - 它是一个说明动态加载的基本文件系统模型,您需要插入自定义逻辑以在 fetchMore
中生成您想要的类别节点称呼。它也只显示文件名而没有图标。
如果您希望显示修改后的日期和大小,您需要将它们存储在相关节点中并将模型 columnCount
方法设置为 return 正确的列数。
对于图标,扩展模型 data
方法以检查 Qt.DecorationRole
和 return 相关的 QIcon
。
代码中可能有一些多余的东西,因为它是从其他东西中删除并重新利用的模型。
import sys
import os
import sip
sip.setapi('QVariant', 2)
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Node(object):
def __init__(self, name, path=None, parent=None):
super(Node, self).__init__()
self.name = name
self.children = []
self.parent = parent
self.is_dir = False
self.path = path
self.is_traversed = False
if parent is not None:
parent.add_child(self)
def add_child(self, child):
self.children.append(child)
child.parent = self
def insert_child(self, position, child):
if position < 0 or position > self.child_count():
return False
self.children.insert(position, child)
child.parent = self
return True
def child(self, row):
return self.children[row]
def child_count(self):
return len(self.children)
def row(self):
if self.parent is not None:
return self.parent.children.index(self)
return 0
class FileSystemTreeModel(QAbstractItemModel):
FLAG_DEFAULT = Qt.ItemIsEnabled | Qt.ItemIsSelectable
def __init__(self, root, path='c:/', parent=None):
super(FileSystemTreeModel, self).__init__()
self.root = root
self.parent = parent
self.path = path
for file in os.listdir(path):
file_path = os.path.join(path, file)
node = Node(file, file_path, parent=self.root)
if os.path.isdir(file_path):
node.is_dir = True
def getNode(self, index):
if index.isValid():
return index.internalPointer()
else:
return self.root
## - dynamic row insertion starts here
def canFetchMore(self, index):
node = self.getNode(index)
if node.is_dir and not node.is_traversed:
return True
return False
## this is where you put custom logic for handling your special nodes
def fetchMore(self, index):
parent = self.getNode(index)
nodes = []
for file in os.listdir(parent.path):
file_path = os.path.join(parent.path, file)
node = Node(file, file_path)
if os.path.isdir(file_path):
node.is_dir = True
nodes.append(node)
self.insertNodes(0, nodes, index)
parent.is_traversed = True
def hasChildren(self, index):
node = self.getNode(index)
if node.is_dir:
return True
return super(FileSystemTreeModel, self).hasChildren(index)
def rowCount(self, parent):
node = self.getNode(parent)
return node.child_count()
## dynamic row insert ends here
def columnCount(self, parent):
return 1
def flags(self, index):
return FileSystemTreeModel.FLAG_DEFAULT
def parent(self, index):
node = self.getNode(index)
parent = node.parent
if parent == self.root:
return QModelIndex()
return self.createIndex(parent.row(), 0, parent)
def index(self, row, column, parent):
node = self.getNode(parent)
child = node.child(row)
if not child:
return QModelIndex()
return self.createIndex(row, column, child)
def headerData(self, section, orientation, role):
return self.root.name
def data(self, index, role):
if not index.isValid():
return None
node = index.internalPointer()
if role == Qt.DisplayRole:
return node.name
else:
return None
def insertNodes(self, position, nodes, parent=QModelIndex()):
node = self.getNode(parent)
self.beginInsertRows(parent, position, position + len(nodes) - 1)
for child in nodes:
success = node.insert_child(position, child)
self.endInsertRows()
return success
app = QApplication(sys.argv)
model = FileSystemTreeModel(Node('Filename'), path='c:/')
tree = QTreeView()
tree.setModel(model)
tree.show()
sys.exit(app.exec_())
我想在 QTreeview 下的 QFileSystemModel 中添加自定义行。仅当目录包含具有特定扩展名的文件时才添加该行。基本上,在启动目录列表后,用户将单击文件夹。一旦用户单击的文件夹包含目标文件,我想隐藏这些文件(我知道该怎么做),然后使用自定义行来表示这些文件的摘要。
例如,如果文件夹包含如下文件
A.01.dat
A.02.dat
A.03.dat
...
B.01.dat
B.02.dat
B.03.dat
我想创建自定义行:
A
B
但是,如果单击的文件夹不包含这些 .dat 文件,则不应创建自定义行。
我也尝试过将行直接插入到 QFileSystemModel
self.treeivew.model = QtGui.QFileSystemModel()
...
for n, s in enumerate(self.sequence):
self.treeview.model.beginInsertRows(index, 0, 0)
result = self.treeview.model.insertRow(1, index)
print(result)
self.treeview.model.setData(index, QString(s['Name']),role=QtCore.Qt.DisplayRole)
self.treeview.model.endInsertRows()
但是插入失败
如果需要重新实现,正如我在很多地方看到的那样,谁能提供一个 具体 示例,说明应该如何重新实现以允许这种有条件的自定义行插入?
提前致谢。
我会实现一个带有动态子项插入的项目模型。这只是一个标准 QAbstractItemModel
和一些额外的方法 -
- rowCount - 你通常会为树模型实现它。如果节点有尚未加载的子节点,请确保它 returns 0。
- hasChildren - 对于具有尚未加载的子节点的节点覆盖到 return
True
并且 return 无论基础 class returns 在所有其他情况下。 - canFetchMore - return
True
如果节点有尚未加载的子节点,False
否则。 - fetchMore - 在这里您可以执行您需要的任何逻辑来决定要创建哪些节点并将它们插入到模型中。
这是基本思路 - 对于您知道的节点有尚未加载的子节点,return 0 来自 rowCount
和 True
来自 canFetchMore
和 hasChildren
。这告诉 Qt 显示一个节点,旁边有一个扩展器,即使它当前没有子节点。单击扩展器时,将调用 fetchMore
并从给定的父级填充子级。
需要注意一件事 - 您必须在 fetchMore
方法中调用 beginInsertRows
和 endInsertRows
。此外,您不得在调用 beginInsertRows
之前或 endInsertRows
之后更改基础数据存储。不幸的是,您需要知道在调用 beginInsertRows
时要插入多少行 - 因此您可能想要生成要添加的节点列表,然后调用 beginInsertRows
。但是,如果您这样做,则无法设置新节点的父节点,因为它会更改底层数据存储。
您可以在下面的代码中看到,我在 Node.insert_child
方法中设置了父节点,该方法在 beginInsertRows
和 endInsertRows
调用之间调用。
该代码并不完全符合您的要求 - 它是一个说明动态加载的基本文件系统模型,您需要插入自定义逻辑以在 fetchMore
中生成您想要的类别节点称呼。它也只显示文件名而没有图标。
如果您希望显示修改后的日期和大小,您需要将它们存储在相关节点中并将模型 columnCount
方法设置为 return 正确的列数。
对于图标,扩展模型 data
方法以检查 Qt.DecorationRole
和 return 相关的 QIcon
。
代码中可能有一些多余的东西,因为它是从其他东西中删除并重新利用的模型。
import sys
import os
import sip
sip.setapi('QVariant', 2)
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Node(object):
def __init__(self, name, path=None, parent=None):
super(Node, self).__init__()
self.name = name
self.children = []
self.parent = parent
self.is_dir = False
self.path = path
self.is_traversed = False
if parent is not None:
parent.add_child(self)
def add_child(self, child):
self.children.append(child)
child.parent = self
def insert_child(self, position, child):
if position < 0 or position > self.child_count():
return False
self.children.insert(position, child)
child.parent = self
return True
def child(self, row):
return self.children[row]
def child_count(self):
return len(self.children)
def row(self):
if self.parent is not None:
return self.parent.children.index(self)
return 0
class FileSystemTreeModel(QAbstractItemModel):
FLAG_DEFAULT = Qt.ItemIsEnabled | Qt.ItemIsSelectable
def __init__(self, root, path='c:/', parent=None):
super(FileSystemTreeModel, self).__init__()
self.root = root
self.parent = parent
self.path = path
for file in os.listdir(path):
file_path = os.path.join(path, file)
node = Node(file, file_path, parent=self.root)
if os.path.isdir(file_path):
node.is_dir = True
def getNode(self, index):
if index.isValid():
return index.internalPointer()
else:
return self.root
## - dynamic row insertion starts here
def canFetchMore(self, index):
node = self.getNode(index)
if node.is_dir and not node.is_traversed:
return True
return False
## this is where you put custom logic for handling your special nodes
def fetchMore(self, index):
parent = self.getNode(index)
nodes = []
for file in os.listdir(parent.path):
file_path = os.path.join(parent.path, file)
node = Node(file, file_path)
if os.path.isdir(file_path):
node.is_dir = True
nodes.append(node)
self.insertNodes(0, nodes, index)
parent.is_traversed = True
def hasChildren(self, index):
node = self.getNode(index)
if node.is_dir:
return True
return super(FileSystemTreeModel, self).hasChildren(index)
def rowCount(self, parent):
node = self.getNode(parent)
return node.child_count()
## dynamic row insert ends here
def columnCount(self, parent):
return 1
def flags(self, index):
return FileSystemTreeModel.FLAG_DEFAULT
def parent(self, index):
node = self.getNode(index)
parent = node.parent
if parent == self.root:
return QModelIndex()
return self.createIndex(parent.row(), 0, parent)
def index(self, row, column, parent):
node = self.getNode(parent)
child = node.child(row)
if not child:
return QModelIndex()
return self.createIndex(row, column, child)
def headerData(self, section, orientation, role):
return self.root.name
def data(self, index, role):
if not index.isValid():
return None
node = index.internalPointer()
if role == Qt.DisplayRole:
return node.name
else:
return None
def insertNodes(self, position, nodes, parent=QModelIndex()):
node = self.getNode(parent)
self.beginInsertRows(parent, position, position + len(nodes) - 1)
for child in nodes:
success = node.insert_child(position, child)
self.endInsertRows()
return success
app = QApplication(sys.argv)
model = FileSystemTreeModel(Node('Filename'), path='c:/')
tree = QTreeView()
tree.setModel(model)
tree.show()
sys.exit(app.exec_())