找回密码
 立即注册
收起左侧

PySide2/PyQt5:如何自定義 QSortFilterProxyModel 顯示特定文件夾

0
回复
4249
查看
[复制链接]
累计签到:1 天
连续签到:1 天
来源: 2019-9-5 12:15:13 显示全部楼层 |阅读模式
1Qter豆
本帖最后由 Upo 于 2019-9-5 12:16 编辑

問題:PySide2/PyQt5:如何自定義 QSortFilterProxyModel 顯示特定文件夾?

要做個定製的文件管理器,只顯示文件夾。想在 treeView 中只顯示普通文件夾,在 listView 中只顯示結尾爲 .asset 的特殊文件夾。類似這樣:



目前我的方法是用兩個獨立的 QFileSystemModel,分別放到兩個 QSortFilterProxyModel 中,一個剔除 .asset 文件夾,另一個只顯示 .asset 文件夾。
但總是不能按預期工作。
界面主要代碼:
root_path = "f:/root_folder"

# 分別建 2 個文件系統模型,用於 treeView 和 listView 顯示不同內容
treeModel = QFileSystemModel()
listModel = QFileSystemModel()

# 模型只顯示文件夾,且不包含 '.' 和 '..':
treeModel.setFilter(QDir.NoDotAndDotDot | QDir.Dirs)
listModel.setFilter(QDir.NoDotAndDotDot | QDir.Dirs)

# 指定根目錄,我只想讓模型搜索 'f:/root_folder':
treeModel.setRootPath(root_path)
listModel.setRootPath(root_path)

# 自定義代理模型 QSortFilterProxyModel:
# 兩個代理使用一個代理模型,經傳入參數切換不同操作。
treeProxy = myProxyModel(False)
treeProxy.setSourceModel(treeModel)
listProxy = myProxyModel(True)
listProxy.setSourceModel(listModel)

# 在 view 中顯示結果
# 'ui' 是 QWidget object,包含 treeView 和 listView.
ui.treeView.setModel(treeProxy)
ui.treeView.setRootIndex(treeProxy.mapFromSource(treeModel.index(root_path)))
ui.listView.setModel(listProxy)
ui.listView.setRootIndex(listProxy.mapFromSource(listModel.index(root_path)))

# 點擊 treeView 發給 listView 信號
# 信號路徑:樹代理索引 -> 樹模型索引 -> 絕對路徑 -> 列表索引 -> 列表代理索引
ui.treeView.clicked.connect(lambda index:
                            ui.listView.setRootIndex(
                                listProxy.mapFromSource(
                                    listModel.setRootPath(
                                        treeModel.fileInfo(
                                            treeProxy.mapToSource(index)
                                        ).absoluteFilePath()
                                    ))
                            ))


我首先測試了 QSortFilterProxyModel,無論如何都返回 True ,也就是不過濾

# test:
class myProxyModel(QSortFilterProxyModel):
    def __init__(self, isAsset=True, parent=None):
        super(myProxyModel, self).__init__(parent)
        self._isAsset = isAsset
    def filterAcceptsRow(self, source_row, source_parent):
        return True


到目前為止一切正常,於是我加入過濾 .asset 的功能。

class myProxyModel(QSortFilterProxyModel):
    def __init__(self, isAsset=True, parent=None):
        super(myProxyModel, self).__init__(parent)
        self._isAsset = isAsset # True 僅顯示 .asset,反之不顯示 .asset
    def filterAcceptsRow(self, source_row, source_parent):
        # 獲得當前路徑下項目的文件名
        source_index = self.sourceModel().index(source_row, 0, source_parent)
        filename = source_index.data(Qt.DisplayRole)
        # 判斷是否爲帶 .asset 的特殊文件夾
        if self._isAsset:
            if filename.endswith(".asset"): return True
            else: return False
        else:
            if filename.endswith(".asset"): return False
            else: return True


結果 listView 是空的。為什麼?

為了研究 filterAcceptsRow() 的工作原理,我又做了個測試:

class myProxyModel(QSortFilterProxyModel):
    def __init__(self, isAsset=True, parent=None):
        super(myProxyModel, self).__init__(parent)
        self._isAsset = isAsset
    def filterAcceptsRow(self, source_row, source_parent):
        if not source_parent.isValid():
            print("error")
            return False
        else: return True


因為沒有任何過濾,所以 treeView, listView 都能正常工作,但控制臺出現 4 個 error 讓我更困惑了。
我對 filterAcceptsRow() 的理解:
你指定一個目錄,filterAcceptsRow() 對目錄內每個項目逐個檢查 ……
但顯然不是這樣。

所以正確的方法是什麽?filterAcceptsRow() 的具體作用又是什麽呢?

附件: 您需要 登录 才可以下载或查看,没有帐号?立即注册
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了