简介
接到一个需求,在Combobox的下来框中,显示一颗树,从树节点中选取项目,如下图所示,记录一下
查看了Qt的官方文档,发现了void QComboBox::setView(QAbstractItemView *itemView)
函数,那么事情似乎就变得简单了,直接构造QTreeView(或者QTreeWidget)对象,然后设置到QCombobox中,似乎就大功告成了。
实验一下:
auto model = new TreeModel(this);
QTreeView *tree = new QTreeView(this);
tree->setHeaderHidden(true);
tree->setModel(model);
ui->comboBox->setView(tree);
ui->comboBox->setModel(model);
tree->expandAll();
短短的几行代码就完成了,以此类推,下拉表格,甚至自定义控制是否都能实现,感兴趣的可以尝试一下。
在初始化时需要使得Combox,选中树节点中的某个孩子节点,使用setRootModelIndex(const QModelIndex &index)
auto parantIndex; //获取到需要设置节点的父亲节点
ui->comboBox->setRootModelIndex(parantIndex); //将当前根节点设置为刚找到的父亲节点
ui->comboBox->setCurrentIndex(1); //设置选中第几个孩子
ui->comboBox->setRootModelIndex(root); //设置完成后将根节点设置为树的根节点
更新
当设置了树为下拉框对象时,发现并不完美,在折叠或展开树的时候,下拉框会自动收起,这非常影响使用,必须的处理。
解决办法也很多,这里提供三种常用的解决方式,如有大佬有更好的解决办法,欢迎指正。
方案一
自定义QComboBox控件,重写其hidePopup()
函数,可以在hidePopup()
函数中判断当前是否能够隐藏,详情见qt官方文档
方案二
将需要能够折叠的item设置为不可选中状态,当然,这种方式存在局限性,只适用于只能选择叶子节点的情况,同事此种办法也是最简单的实现方式。只需要在创建树节点时设置其不可选中即可
item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
方案三
设置事件过滤器,经过研究发现,下拉框实在鼠标弹起时隐藏,因此,我们只需要在鼠标弹起时判断是在哪个区域即可。
//设置事件过滤器
ui->comboBox->view()->viewport()->installEventFilter(this);
//事件处理函数
bool MainWindow::eventFilter(QObject *watch, QEvent *e)
{
if(watch == ui->comboBox->view()->viewport() && e->type() == QEvent::MouseButtonRelease)
{
//判断点的是否是折叠按钮
QMouseEvent *_mouse = static_cast<QMouseEvent*>(e);
if(nullptr == _mouse)
{
return false;
}
auto _rect = m_tree->visualItemRect(m_tree->currentItem());
if(!_rect.contains(_mouse->pos()))
{
return true;
}
}
return QMainWindow::eventFilter(watch,e);
}
看个效果
代码还是放在这里了
链接