Qt6.2.4中QComboBox(配QTreeView)同层级项键盘选中视图不更新问题
Qt 6.2.4树形ComboBox上下箭头切换兄弟节点不更新视图问题
环境与背景
- 运行环境:Ubuntu,Qt 6.2.4
- 实现逻辑:继承
QComboBox,将QTreeView设置为其视图,用于展示多级文件夹与文件的树形结构 - 当前状态:组件基础功能正常,现需实现选中某一项后,通过上下箭头键选中同一父节点的上一个/下一个兄弟项
问题现象
已在keyPressEvent()中正确获取到目标兄弟节点的QModelIndex,但ComboBox始终显示之前选中的项,视图无更新。尝试过代码中注释的多种方法均无效。
代码实现
main.cpp
#include <QApplication> #include "tree-combobox.h" int main(int argc, char **argv) { QApplication app (argc, argv); TreeComboBox combo; combo.setGeometry(0, 0, 400, 50); combo.ShowFileList("/my/path/", "*"); combo.show(); return app.exec(); }
tree-combobox.h
#include <QComboBox> #include <QTreeView> #include <QFileSystemModel> #include <QMouseEvent> #include <QAbstractItemView> class TreeComboBox : public QComboBox { public: TreeComboBox(QWidget* parent = 0) : QComboBox(parent) { QTreeView* tree = new QTreeView(this); // tree view for combobox setView(tree); // assign it to combobox } void ShowFileList(QString path, QString filesFilter) // fill combobox with folders and files, specify path and wildcard(s) { // block signals this->blockSignals(true); // no signals emitted while stuffing the widget //// create files model QFileSystemModel *fileModel = new QFileSystemModel(this); // file system model to use // set options to file model fileModel->setReadOnly(true); // set it read-only fileModel->setFilter(QDir::AllDirs | QDir::AllEntries |QDir::NoDotAndDotDot); // all folders, all files, no file beginning with a dot fileModel->setOption(QFileSystemModel::DontUseCustomDirectoryIcons); // don't use icons from the files fileModel->setOption(QFileSystemModel::DontWatchForChanges); // the widget won't track changes on disk // set file filter for files model QStringList filter; // for files wildcard filter << filesFilter; fileModel->setNameFilters(filter); // set root for files model fileModel->setRootPath(""); //// create view // tree view QTreeView *view = new QTreeView; this->setView(view); // assign tree view to combobox // files model this->setModel(fileModel); // assign files model to combobox // remove columns in tree view, to keep only filenames QModelIndex index = fileModel->index(path); for (int i = 1; i < fileModel->columnCount(); ++i) // all columns but first one view->hideColumn(i); // tree view options view->setAnimated(true); // animated view->setSortingEnabled(true); // sorting enabled by clicking on header view->sortByColumn(0, Qt::AscendingOrder); // sort values view->expand(index); // expand the view from the given path view->scrollTo(index); // set view from given path view->setRootIndex(index); // set root index to given path // allow signals again this->blockSignals(false); } QString GetFile() // get selected value from list // currentItemChanged() is emitted each time an item is clicked, even a parent item // this function returns an empty QString if the clicked item is not valid (i.e. a folder) { QModelIndex index = view()->currentIndex(); // current value index from QTree QString path = model()->data(index, QFileSystemModel::FilePathRole).toString(); // get full path value QFileInfo info(path); // to test this value if (info.isFile()) // if the value is really a file return path; // ... return its full path else // value is a folder return QString(); // ... so return nothing } private: virtual void hidePopup() // control popup hiding behaviour // for a combobox, each time an item is clicked the popup disappears... but not for a folder this time ! { if (!view()->underMouse()) { // is mouse over QTreeView ? QComboBox::hidePopup(); // if not collapse the comboBox return; } QModelIndex index = view()->currentIndex(); // get current index of selected item if (!model()->hasChildren(index)) // if it doesn't have children (so it is not a folder) QComboBox::hidePopup(); // collapse the comboBox } virtual void keyPressEvent(QKeyEvent *keyboardEvent) // keyboard event { if (this->hasFocus()) { // widget has to be active to accept keyboard keys if (keyboardEvent->key() == Qt::Key_Up) { // up //view()->setCurrentIndex(view()->currentIndex().sibling(view()->currentIndex().row() - 1, 0)); //view()->selectionModel()->select(view()->currentIndex(), QItemSelectionModel::Select | QItemSelectionModel::Rows); QModelIndex index = view()->currentIndex(); int n = index.row() - 1; QModelIndex sibling = index.siblingAtRow(n); if (sibling.isValid()) { view()->setCurrentIndex(sibling); view()->scrollTo(sibling); //view()->selectionModel()->setCurrentIndex(sibling, QItemSelectionModel::ClearAndSelect); //view()->selectionModel()->select(sibling, QItemSelectionModel::Select | QItemSelectionModel::Rows); //tree->selectionModel()->select(tree->currentIndex(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); //this->setCurrentIndex(sibling.row()); } keyboardEvent->accept(); // accept keyboard event } else if (keyboardEvent->key() == Qt::Key_Down) { // down view()->setCurrentIndex(view()->currentIndex().sibling(view()->currentIndex().row() - 1, 0)); keyboardEvent->accept(); } } } };
尝试过的方法
keyPressEvent()中注释掉的所有方法,包括:
- 直接调用
view()->setCurrentIndex()设置兄弟节点 - 通过
selectionModel执行选择操作 - 调用
this->setCurrentIndex()
期望结果
按下上下箭头时,ComboBox选中并显示同一父节点的上一个/下一个项,不会切换到其他父节点的项。
内容的提问来源于stack exchange,提问作者AbsurdePhoton
相关产品推荐
相关产品推荐

