You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 16:25:11