如何在 PySide/Qt QColumnView 中取消选择列

问题描述 投票:0回答:1

我正在创建一个简单的文件浏览器,并尝试实现像 macOS Finder 中那样的 Miller Columns。 Qt 提供了

QColumnView
QFileSystemModel
,这应该可以轻松组合并获得我想要的功能。

但是,如果您单击几级目录,然后单击当前目录上几级的空白区域,视图不会改变。突出显示将从您单击的文件夹中删除,但这是视觉效果的唯一更改。

作为我正在尝试做的示例,顶部是 Finder,底部是我当前的应用程序:

我已经尝试拦截尽可能多的

Signals
Slots
,包括
pressed
clicked
entered
selectionModel().currentRowChanged
UpdateRequest
来覆盖Qt的行为并设置正确的
 currentIndex
,但尚未发现模型或视图中的状态信息对于设置正确的索引有用。

我还尝试记录每个事件(使用裸的

def event()
覆盖),当我在根文件夹中单击取消选择时,似乎甚至没有触发
event

MCVE:

from pathlib import Path

from PySide6.QtWidgets import (
    QApplication,
    QFileSystemModel,
    QColumnView,
    QMainWindow,
)


class CustomColumns(QColumnView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)


class BrowserWindow(QMainWindow):
    def __init__(self, location=None):
        super().__init__()
        if location is None:
            location = Path.home()
        location = Path(location)
        self.setGeometry(625, 333, 1395, 795)
        self.setWindowTitle(location.name)

        self._root = str(location)
        self._files = QFileSystemModel()
        self._files.setRootPath(self._root)

        self._view = CustomColumns()
        self._view.setModel(self._files)

        self.setCentralWidget(self._view)

    def show(self):
        super().show()
        self._view.setRootIndex(self._files.index(self._root))


class FileBrowser(QApplication):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setQuitOnLastWindowClosed(False)
        self.window = BrowserWindow(location=Path.home())
        self.window.show()


def main():
    app = FileBrowser()
    app.exec()


if __name__ == "__main__":
    main()
python qt selection pyside6 qcolumnview
1个回答
0
投票

这里的问题是

QColumnView
实际上是由一系列
QListView
列组成。因此,在尝试处理大多数信号和事件时,列视图本身并没有多大帮助。解决此问题的一种方法是重新实现 createColumn 并在每个视图的视口上安装事件过滤器,以便可以跟踪相关的鼠标事件。这是必要的,因为点击空白区域时,
QListView
的内置信号不会触发。

下面是一个基本演示,展示了实现此目的的一种方法。一个单独的

QObject
类用于监视事件,以免干扰列视图的现有事件过滤器。单击任何列的空白区域会将当前索引移动到单击的列:

from pathlib import Path
from PySide6.QtWidgets import (
    QApplication, QFileSystemModel, QColumnView, QMainWindow, QListView,
    )
from PySide6.QtCore import (
    QEvent, QObject, Signal, QModelIndex,
    )

class ColumnWatcher(QObject):
    columnClicked = Signal(QModelIndex, bool)

    def eventFilter(self, source, event):
        try:
            if (isinstance(view := source.parent(), QListView) and
                event.type() == QEvent.MouseButtonPress):
                index = view.indexAt(event.position().toPoint())
                self.columnClicked.emit(view.rootIndex(), not index.isValid())
            return super().eventFilter(source, event)
        except RuntimeError:
            return False

class CustomColumns(QColumnView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._watcher = ColumnWatcher(self)
        self._watcher.columnClicked.connect(self.handleClicked)

    def createColumn(self, index):
        view = super().createColumn(index)
        view.viewport().installEventFilter(self._watcher)
        return view

    def handleClicked(self, root, blank):
        if blank:
            if root != self.rootIndex():
                self.setCurrentIndex(root)
            else:
                self.setRootIndex(root)
                self.setCurrentIndex(QModelIndex())

class BrowserWindow(QMainWindow):
    def __init__(self, location=None):
        super().__init__()
        if location is None:
            location = Path.home()
        location = Path(location)
        self.setGeometry(625, 333, 1395, 795)
        self.setWindowTitle(location.name)

        self._root = str(location)
        self._files = QFileSystemModel()
        self._files.setRootPath(self._root)

        self._view = CustomColumns()
        self._view.setModel(self._files)

        self.setCentralWidget(self._view)

    def showEvent(self, event):
        self._view.setRootIndex(self._files.index(self._root))

class FileBrowser(QApplication):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setQuitOnLastWindowClosed(False)
        self.window = BrowserWindow(location=Path.home())
        self.window.show()

def main():
    app = FileBrowser()
    app.exec()

if __name__ == "__main__":
    main()
© www.soinside.com 2019 - 2024. All rights reserved.