Qt:如何处理 QAbstractItemView 的焦点变化
Posted
技术标签:
【中文标题】Qt:如何处理 QAbstractItemView 的焦点变化【英文标题】:Qt: How do you handle focus changes for a QAbstractItemView 【发布时间】:2020-09-07 09:09:26 【问题描述】:我想做的就是知道用户何时按下 ctrl + 向上箭头/向下箭头来聚焦列表中的项目。我希望我可以区分用户关注项目和选择项目。
我有一个 QAbstractItemView
的实现,我已经覆盖了它
::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
以及
::currentChanged(const QModelIndex& current, const QModelIndex& previous)
阅读https://doc.qt.io/archives/qtjambi-4.5.2_01/com/trolltech/qt/model-view-selection.html 后我的理解是,如果我用ctrl + up arrow
聚焦一个项目,我将得到一个currentChanged
事件。如果我通过up arrow
选择某些内容,我将获得selectionChanged
事件。
但是,事实并非如此。按ctrl + up arrow
会导致selectionChanged
和currentChanged
都被解雇。我不知道为什么一旦我进入这些功能就会被解雇。当我在selectionChanged
时,我不知道我为什么在那里。是因为专注吗?是因为选择吗?
有件事可能应该告诉我QItemSelectionModel.SelectionFlag
,但我显然也无权访问这些。
那么发生了什么?这是一个错误吗?同样,我想做的只是列表中的焦点项目。
qt 版本 5.9
【问题讨论】:
建议:不要把你的不满转移到你的帖子上,因为它会转移到我们这些想要帮助你的人身上,而且它会分散我们的注意力并且不会带来任何信息。 @eyllanesc,此建议制定得非常好,值得以某种方式纳入 SO。 它的中肯建议,感谢。 我只想指出您的文档链接看起来非常非常旧。也许它仍然是准确的,但也许不是?我会开始here。 【参考方案1】:我试图重现 OP 描述的问题。
不幸的是,OP 没有提供MCVE。所以,我自己做了一个:
// Qt header:
#include <QtWidgets>
class ListWidget: public QListWidget
public:
ListWidget(QWidget *pQParent = nullptr): QListWidget(pQParent)
virtual ~ListWidget() = default;
ListWidget(const ListWidget&) = delete;
ListWidget& operator=(const ListWidget&) = delete;
virtual void currentChanged(
const QModelIndex ¤t, const QModelIndex &previous) override
qDebug() << "currentChanged():" << previous << "->" << current;
QListWidget::currentChanged(current, previous);
virtual void selectionChanged(
const QItemSelection &selected, const QItemSelection &deselected) override
qDebug() << "selectionChanged():" << selected << "->" << deselected;
QListWidget::selectionChanged(selected, deselected);
;
void populate(QListWidget &qLst)
const int n = 10;
for (int i = 1; i <= n; ++i)
new QListWidgetItem(QString("item %1").arg(i), &qLst);
// main application
int main(int argc, char **argv)
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
ListWidget qLst;
qLst.setSelectionMode(QListWidget::ExtendedSelection);
populate(qLst);
qLst.show();
// runtime loop
return app.exec();
在VS2017中用Qt5.13编译:
输出:
Qt Version: 5.13.0
currentChanged(): QModelIndex(-1,-1,0x0,QObject(0x0)) -> QModelIndex(0,0,0x2adc4f38610,QListModel(0x2adc4f3a3a0))
我用 Shift ↓ 选择了前 5 个项目:
currentChanged(): QModelIndex(0,0,0x2adc4f38610,QListModel(0x2adc4f3a3a0)) -> QModelIndex(1,0,0x2adc4f38a00,QListModel(0x2adc4f3a3a0))
selectionChanged(): (QItemSelectionRange(QModelIndex(0,0,0x2adc4f38610,QListModel(0x2adc4f3a3a0)),QModelIndex(0,0,0x2adc4f38610,QListModel(0x2adc4f3a3a0))), QItemSelectionRange(QModelIndex(1,0,0x2adc4f38a00,QListModel(0x2adc4f3a3a0)),QModelIndex(1,0,0x2adc4f38a00,QListModel(0x2adc4f3a3a0)))) -> ()
currentChanged(): QModelIndex(1,0,0x2adc4f38a00,QListModel(0x2adc4f3a3a0)) -> QModelIndex(2,0,0x2adc4f38a70,QListModel(0x2adc4f3a3a0))
selectionChanged(): (QItemSelectionRange(QModelIndex(2,0,0x2adc4f38a70,QListModel(0x2adc4f3a3a0)),QModelIndex(2,0,0x2adc4f38a70,QListModel(0x2adc4f3a3a0)))) -> ()
currentChanged(): QModelIndex(2,0,0x2adc4f38a70,QListModel(0x2adc4f3a3a0)) -> QModelIndex(3,0,0x2adc4f38ae0,QListModel(0x2adc4f3a3a0))
selectionChanged(): (QItemSelectionRange(QModelIndex(3,0,0x2adc4f38ae0,QListModel(0x2adc4f3a3a0)),QModelIndex(3,0,0x2adc4f38ae0,QListModel(0x2adc4f3a3a0)))) -> ()
currentChanged(): QModelIndex(3,0,0x2adc4f38ae0,QListModel(0x2adc4f3a3a0)) -> QModelIndex(4,0,0x2adc4f38f40,QListModel(0x2adc4f3a3a0))
selectionChanged(): (QItemSelectionRange(QModelIndex(4,0,0x2adc4f38f40,QListModel(0x2adc4f3a3a0)),QModelIndex(4,0,0x2adc4f38f40,QListModel(0x2adc4f3a3a0)))) -> ()
然后我使用 Ctrl ↓ 将焦点移动到item 10
:
currentChanged(): QModelIndex(4,0,0x2adc4f38f40,QListModel(0x2adc4f3a3a0)) -> QModelIndex(5,0,0x2adc4f3f990,QListModel(0x2adc4f3a3a0))
currentChanged(): QModelIndex(5,0,0x2adc4f3f990,QListModel(0x2adc4f3a3a0)) -> QModelIndex(6,0,0x2adc4f3f6f0,QListModel(0x2adc4f3a3a0))
currentChanged(): QModelIndex(6,0,0x2adc4f3f6f0,QListModel(0x2adc4f3a3a0)) -> QModelIndex(7,0,0x2adc4f3f1b0,QListModel(0x2adc4f3a3a0))
currentChanged(): QModelIndex(7,0,0x2adc4f3f1b0,QListModel(0x2adc4f3a3a0)) -> QModelIndex(8,0,0x2adc4f3f840,QListModel(0x2adc4f3a3a0))
currentChanged(): QModelIndex(8,0,0x2adc4f3f840,QListModel(0x2adc4f3a3a0)) -> QModelIndex(9,0,0x2adc4f3f7d0,QListModel(0x2adc4f3a3a0))
这在我看来是合理的 - 正如 OP 所报告的那样,没有对 selectionChanged()
的不必要调用。
可以肯定的是,我在cygwin中编译了相同的代码并再次尝试:
$ qmake-qt5
Info: creating stash file /cygdrive/d/ds32737/Entwicklung/tests/Qt/QAbstractItemViewCurrentChanged/.qmake.stash
$ make && ./testQAbstractItemViewCurrentChanged
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQAbstractItemViewCurrentChanged.o testQAbstractItemViewCurrentChanged.cc
g++ -o testQAbstractItemViewCurrentChanged.exe testQAbstractItemViewCurrentChanged.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
Qt Version: 5.9.4
currentChanged(): QModelIndex(-1,-1,0x0,QObject(0x0)) -> QModelIndex(0,0,0x60014b260,QListModel(0x6000df6b0))
currentChanged(): QModelIndex(0,0,0x60014b260,QListModel(0x6000df6b0)) -> QModelIndex(1,0,0x60014ba60,QListModel(0x6000df6b0))
selectionChanged(): (QItemSelectionRange(QModelIndex(0,0,0x60014b260,QListModel(0x6000df6b0)),QModelIndex(0,0,0x60014b260,QListModel(0x6000df6b0))), QItemSelectionRange(QModelIndex(1,0,0x60014ba60,QListModel(0x6000df6b0)),QModelIndex(1,0,0x60014ba60,QListModel(0x6000df6b0)))) -> ()
currentChanged(): QModelIndex(1,0,0x60014ba60,QListModel(0x6000df6b0)) -> QModelIndex(2,0,0x60014bb20,QListModel(0x6000df6b0))
selectionChanged(): (QItemSelectionRange(QModelIndex(2,0,0x60014bb20,QListModel(0x6000df6b0)),QModelIndex(2,0,0x60014bb20,QListModel(0x6000df6b0)))) -> ()
currentChanged(): QModelIndex(2,0,0x60014bb20,QListModel(0x6000df6b0)) -> QModelIndex(3,0,0x60014bc30,QListModel(0x6000df6b0))
selectionChanged(): (QItemSelectionRange(QModelIndex(3,0,0x60014bc30,QListModel(0x6000df6b0)),QModelIndex(3,0,0x60014bc30,QListModel(0x6000df6b0)))) -> ()
currentChanged(): QModelIndex(3,0,0x60014bc30,QListModel(0x6000df6b0)) -> QModelIndex(4,0,0x60014bd20,QListModel(0x6000df6b0))
selectionChanged(): (QItemSelectionRange(QModelIndex(4,0,0x60014bd20,QListModel(0x6000df6b0)),QModelIndex(4,0,0x60014bd20,QListModel(0x6000df6b0)))) -> ()
currentChanged(): QModelIndex(4,0,0x60014bd20,QListModel(0x6000df6b0)) -> QModelIndex(5,0,0x60014be10,QListModel(0x6000df6b0))
currentChanged(): QModelIndex(5,0,0x60014be10,QListModel(0x6000df6b0)) -> QModelIndex(6,0,0x60014bf00,QListModel(0x6000df6b0))
currentChanged(): QModelIndex(6,0,0x60014bf00,QListModel(0x6000df6b0)) -> QModelIndex(7,0,0x60014bbb0,QListModel(0x6000df6b0))
currentChanged(): QModelIndex(7,0,0x60014bbb0,QListModel(0x6000df6b0)) -> QModelIndex(8,0,0x60014c120,QListModel(0x6000df6b0))
currentChanged(): QModelIndex(8,0,0x60014c120,QListModel(0x6000df6b0)) -> QModelIndex(9,0,0x60014c210,QListModel(0x6000df6b0))
所以,我再次无法复制。报告的事件与我使用 VS2017 得到的事件相当。
请注意,我已经在 cygwin 上安装了 Qt5.9.4——OP 声称拥有的版本。
【讨论】:
啊,我明白了。所以它真的应该只在焦点改变时调用 currentChanged 。我应该提到我没有使用 QListWidgets。我不确定这是否重要。我正在使用 QStyledItemDelegate。不确定这是否重要。我想我会尝试在一个小例子中设计一些东西 @JoshSanders 尝试使用尽可能小的minimal reproducible example 重现您的问题。我使用QListWidget
将代码 fpr 填充等保持在最低限度。如果这是QAbstractItemView
的问题,它不应该有所作为。我不确定QStyledItemDelegate
在什么情况下起作用(但恕我直言,它不应该)。
@JoshSanders 你在什么操作系统/平台上?以上是关于Qt:如何处理 QAbstractItemView 的焦点变化的主要内容,如果未能解决你的问题,请参考以下文章
"Qt Qtwebengineprocess已停止工作",该如何处理
Qt Qtwebengineprocess已停止工作,该如何处理