pyqt4中的条件自定义行QFileSystemModel

时间:2016-02-07 20:09:18

标签: qt pyqt4

我想在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()

但插入失败。

如果需要重新实现,正如我已经看到许多地方所建议的那样,是否有人可以提供一个具体示例,说明如何进行重新实现以允许这种条件自定义行插入?

提前致谢。

1 个答案:

答案 0 :(得分:0)

我会用动态子插入实现项目模型。这只是一个标准QAbstractItemModel,有一些额外的方法 -

  • rowCount - 无论如何,您通常会为树模型实现此功能。如果节点还有尚未加载的子节点,请确保它返回0。
  • hasChildren - 覆盖以返回具有尚未加载的子节点的节点True,并返回基类在所有其他情况下返回的内容。
  • canFetchMore - 如果节点中有子节点尚未加载,则返回True,否则返回False
  • fetchMore - 您可以在此处执行所需的逻辑,以确定要创建的节点并将其插入模型中。

这是基本想法 - 对于您知道有未加载子项的节点,从rowCount返回0,从TruecanFetchMore返回hasChildren。这告诉Qt显示一个节点旁边有一个扩展器,即使它当前没有子节点。单击扩展器时,将调用fetchMore并填充给定父级的子级。

有一点需要注意 - 您必须在beginInsertRows方法中调用endInsertRowsfetchMore。更重要的是,在调用beginInsertRows之前或endInsertRows之后,您不会更改基础数据存储区。不幸的是,当你调用beginInsertRows时,你需要知道插入了多少行 - 所以你可能想要生成要添加的节点列表,然后调用beginInsertRows。如果以这种方式执行此操作,则无法设置新节点的父节点,因为它将更改基础数据存储区。

您可以在下面的代码中看到,我在Node.insert_child方法中设置父节点,该方法在beginInsertRowsendInsertRows来电之间调用。

代码并不完全符合您的要求 - 它是一个说明动态加载的基本文件系统模型,您需要插入自定义逻辑以在fetchMore调用中生成所需的类别节点。它也只显示文件名并缺少图标。

如果要显示修改后的日期和大小,则需要将它们存储在相关节点中,并设置模型columnCount方法以返回正确的列数。

对于图标,请扩展模型data方法以检查Qt.DecorationRole并返回相关的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_())