有隐藏项时关注下一个 QListWidget 项

Focusing on the next QListWidget item while there are hidden items

在说我的问题之前,我想先说说我想做什么。

如果我用鼠标单击 Qlistwidget 并将焦点放在那里,即使有隐藏的项目,我也可以使用键盘(up/down 箭头键)关注下一个项目。系统自动完成,无需编写任何代码。

但我想在不失去对 QLineEdit 的关注的情况下做到这一点。所以我决定使用 QShortcut:

self.__up_key = QShortcut(Qt.Key_Up, self)
self.__dw_key = QShortcut(Qt.Key_Down, self)

self.__up_key.activated.connect(self.__ctrl)
self.__dw_key.activated.connect(self.__ctrl)

def __ctrl(self):
    curr = self._list_widget.currentRow()
    if self.sender().key().toString() == "Up": 
        self._list_widget.setCurrentRow(curr - 1)
    else:
        self._list_widget.setCurrentRow(curr + 1)

在没有隐藏物品的情况下是这样的。但是如果有隐藏的项目,它们的索引仍然存在,所以即使下一个项目被隐藏,它也会选择它。这个当然看不到了。

而我得出这样的结论:

def __ctrl(self):
    if self.sender().key().toString() == "Up":
        self._list_widget.setCurrentRow(self.prevVisibleItem())
    else:
        self._list_widget.setCurrentRow(self.nextVisibleItem())

def nextVisibleItem(self):
    for row in range(self._list_widget.currentRow() + 1, self._list_widget.count()):
        if not self._list_widget.isRowHidden(row):
            return row
    return self._list_widget.currentRow()

def prevVisibleItem(self):
    for row in range(self._list_widget.currentRow() - 1, -1, -1):
        if not self._list_widget.isRowHidden(row):
            return row
    return self._list_widget.currentRow()

我检查每个项目是否隐藏。这对我有用,但我正在寻找一种更有效的方法。当我专注于 QListWidget 时,我可以在每个项目之间导航而无需编写任何代码。我想知道这是怎么发生的。

最小示例:

import sys

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QListWidget, QLineEdit, QShortcut


class Window(QWidget):

    def __init__(self):
        super().__init__()
        self._layout = QVBoxLayout()

        self.entry = QLineEdit()
        self.entry.setPlaceholderText("Search")

        self._list_widget = QListWidget()
        __items = [str(i) + "- item" for i in range(6)]
        self._list_widget.addItems(__items)

        __hidden_items = [self._list_widget.item(1), self._list_widget.item(3), self._list_widget.item(5)]

        for i in __hidden_items:
            i.setHidden(True)

        self.__up_key = QShortcut(Qt.Key_Up, self)
        self.__dw_key = QShortcut(Qt.Key_Down, self)

        self.__up_key.activated.connect(self.__ctrl)
        self.__dw_key.activated.connect(self.__ctrl)

        self._layout.addWidget(self.entry)
        self._layout.addWidget(self._list_widget)
        self.setLayout(self._layout)
        self.show()

    def __ctrl(self):
        if self.sender().key().toString() == "Up":
            self._list_widget.setCurrentRow(self.prevVisibleItem())
        else:
            self._list_widget.setCurrentRow(self.nextVisibleItem())

    def nextVisibleItem(self):
        for row in range(self._list_widget.currentRow() + 1, self._list_widget.count()):
            if not self._list_widget.isRowHidden(row):
                return row
        return self._list_widget.currentRow()

    def prevVisibleItem(self):
        for row in range(self._list_widget.currentRow() - 1, -1, -1):
            if not self._list_widget.isRowHidden(row):
                return row
        return self._list_widget.currentRow()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec_())

更优雅的解决方案是使用 moveCursor 获取 QModelIndex 并将当前索引设置为视图:

def __ctrl(self):
    shorcut = self.sender()
    index = QModelIndex()
    if shorcut.key() == QKeySequence(Qt.Key_Up):
        index = self._list_widget.moveCursor(
            QAbstractItemView.MoveUp, Qt.NoModifier
        )
    elif shorcut.key() == QKeySequence(Qt.Key_Down):
        index = self._list_widget.moveCursor(
            QAbstractItemView.MoveDown, Qt.NoModifier
        )
    if index.isValid():
        self._list_widget.setCurrentIndex(index)