一、需求
QComboBox下拉弹出QTreeView,点击不闭关下拉框,QTreeView有下级节点,点击选中并展开子节点,双击选中并关闭下拉框,在QComboBox外点击则关闭下拉框。
二、解决思路
QComboBox下拉弹出QTreeView可以通过setView和setModel这两个方法实现。
QComboBox的下拉框和弹出和关闭可以通过重写 showPopup和 hidePopup这两个方法进行控制,通过一个bool值变量控制下拉框是否允许关闭。实现过程发现会造成下拉框外在QComboBox上的点击下拉框不会关闭,为此通过事件过滤解决该bug。
三、代码实现
treecombobox.h
#ifndef TREECOMBOBOX_H
#define TREECOMBOBOX_H
#include <QComboBox>
#include <QTreeView>
#include <QEvent>
class TreeComboBox : public QComboBox
{
Q_OBJECT
public:
TreeComboBox(QTreeView* treeView,QAbstractItemModel *model,QWidget *parent = nullptr);
bool eventFilter(QObject *object, QEvent *event);
protected:
void showPopup();
void hidePopup();
private:
bool m_isPermitHidePopup;
signals:
private slots:
void viewDoubleClicked(const QModelIndex &index);
public slots:
};
#endif // TREECOMBOBOX_H
treecombobox.cpp
#include "treecombobox.h"
#include <QMouseEvent>
TreeComboBox::TreeComboBox(QTreeView *treeView, QAbstractItemModel *model, QWidget *parent) : QComboBox(parent)
{
treeView->setModel(model);
setView(treeView);
setModel(model);
connect(treeView,SIGNAL(doubleClicked(const QModelIndex &)),this,SLOT(viewDoubleClicked(const QModelIndex&)));
treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
installEventFilter(this);
//frame为弹出下拉框,注册事件过滤器处理关闭事件的bug
QFrame* frame=this->findChild<QFrame*>();
if(frame)
{
frame->installEventFilter(this);
}
}
bool TreeComboBox::eventFilter(QObject *object, QEvent *event)
{
QFrame* frame=this->findChild<QFrame*>();
if(frame&&frame==object)
{
if(event->type()==QEvent::MouseButtonPress)
{
QMouseEvent* mouseEvent=static_cast<QMouseEvent*>(event);
QPoint globalPos=mouseEvent->globalPos();
QRect rect(frame->mapToGlobal(QPoint(0,0)),QSize(frame->width(),frame->height()));
//鼠标按下位置不在下拉框内则关闭下拉框
if(!rect.contains(globalPos))
{
m_isPermitHidePopup=true;
}
}
}
return QComboBox::eventFilter(object,event);
}
void TreeComboBox::showPopup()
{
QComboBox::showPopup();
m_isPermitHidePopup=false;
}
void TreeComboBox::hidePopup()
{
if(m_isPermitHidePopup)
{
QComboBox::hidePopup();
}
}
void TreeComboBox::viewDoubleClicked(const QModelIndex &index)
{
m_isPermitHidePopup=true;
hidePopup();
}
测试代码main.cpp
#include <QApplication>
#include<QDirModel>
#include"treecombobox.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDirModel * model = new QDirModel ();
QTreeView * view = new QTreeView ();
TreeComboBox * combo = new TreeComboBox(view,model);
combo->resize(700,36);
combo->show();
return a.exec();
}
四、代码下载