Qcombox拉下一树形结构显示,这里提供具体的实现逻辑,分别由 窗体、数据层管理结构设计、QAbstractItemModel,每一个节点的数据信息,实现代码,实现关键是setModel 和setView的使用
第一、每一个节点的数据结构形式
#pragma once
#include
#include
#include
#include
#include
class TreeViewDataInfo;
typedef QList
class TreeViewDataInfo
{
public:
TreeViewDataInfo(TreeViewDataInfo* pParent = NULL);
~TreeViewDataInfo();
int childCount() const;
//存在子信息
int childExists(const TreeViewDataInfo* pMap) const;
TreeViewDataInfo* parentInfo() const;
public:
QString m_TreeItmeName;
TreeViewDataInfoList m_ChildList; //子节点的集合
TreeViewDataInfo* m_pParentInfo; // 父节点信息
int m_childCount;
};
第二、数据层管理管理设计
class TreeViewItem : public QObject
{
public:
explicit TreeViewItem(TreeViewDataInfo* pMapInfo, TreeViewItem* pParent = NULL);
~TreeViewItem();
public:
//获取父项
TreeViewItem* parent() const;
// 获取子项
TreeViewItem* child(int nIndex) const;
// 增加子项
void appendChild(TreeViewItem* pItem);
// 获取子项个数
int childCount() const;
//获取子项索引
int childIndex(const TreeViewItem* pItem) const;
// 删除子项
bool removeChild(int nIndex);
// 获取列数据
QVariant data(int nCol, int role = Qt::DisplayRole);
// 设置列数据
bool setData(int nCol, QVariant val, int role = Qt::EditRole);
//行号
int row() const;
//树Itme项的标志
Qt::ItemFlags flags(int nCol) const;
//获取数据
TreeViewDataInfo* DataInfo() const;
//交换子项位置
bool swapChild(int nFirst, int nSecond);
private:
TreeViewDataInfo* m_pDataInfo;
TreeViewItem* m_pParent; // 父项
QList
};
第三、model数据的实现
class ComboxTreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit ComboxTreeModel(QObject* parent = NULL);
~ComboxTreeModel();
void updataModelTree(TreeViewDataInfoList MapList); //更新treeView中的节点信息
TreeViewItem *getRootItem() { return m_pRootItem; };
public:
TreeViewItem* itemFromIndex(QModelIndex index) const; //从index 里获取具体的item信息
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const { return 1; };
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
virtual QModelIndex parent(const QModelIndex &child) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
TreeViewItem* appendItem(TreeViewDataInfo* pDataInfo, TreeViewItem* pParentItem);
QVariant bulidData(TreeViewItem* pItem, int nCol, int role = Qt::DisplayRole) const;
private:
TreeViewDataInfoList m_mapInfos;
TreeViewItem* m_pRootItem;
TreeViewDataInfo* m_pForRoot;
};
第四、窗体类
class TestDialog : public QDialog
{
Q_OBJECT
public:
TestDialog(QWidget* parent);
~TestDialog();
void refreshModelData(TreeViewDataInfoList DataList);
void setDefaultSelectItem(QString strItemName =QString(""));//根据显示的item去设置默认的选项
private:
void initUI();
private:
ComboxTreeModel *m_pTreeModel;
QTreeView *m_pTreeView;
QComboBox *m_pCombox;
};
第五、对应接口的的实现
#include "QcomboxTree.h"
#include
#include
#include
#include
(1)每一个节点的数据结构形式实现
TreeViewDataInfo::TreeViewDataInfo(TreeViewDataInfo* pParent /*= NULL*/):m_pParentInfo(pParent)
{
m_TreeItmeName ="";
m_ChildList.clear();
m_childCount =-1;
}
TreeViewDataInfo::~TreeViewDataInfo()
{
if (!m_ChildList.isEmpty())
{
TreeViewDataInfoList::iterator b = m_ChildList.begin();
TreeViewDataInfoList::iterator e = m_ChildList.end();
for (; b != e; b++)
{
TreeViewDataInfo* pInfo = *b;
if (NULL != pInfo)
{
delete pInfo;
pInfo = NULL;
}
}
m_ChildList.clear();
}
}
int TreeViewDataInfo::childCount() const
{
return m_ChildList.size();
}
int TreeViewDataInfo::childExists(const TreeViewDataInfo* pDataInf) const
{
TreeViewDataInfoList::const_iterator pos = std::find(m_ChildList.begin(), m_ChildList.end(), pDataInf);
if (pos != m_ChildList.end())
{
return pos - m_ChildList.begin();
}
return -1;
}
TreeViewDataInfo* TreeViewDataInfo::parentInfo() const
{
return m_pParentInfo;
}
(2)数据层管理层实现
TreeViewItem::TreeViewItem(TreeViewDataInfo* pMapInfo, TreeViewItem* pParent /*= NULL*/)
:m_pDataInfo(pMapInfo),m_pParent(pParent)
{
}
TreeViewItem::~TreeViewItem()
{
}
TreeViewItem* TreeViewItem::parent() const
{
return m_pParent;
}
TreeViewItem* TreeViewItem::child(int nIndex) const
{
if (nIndex < 0 && nIndex >= childCount())
{
return NULL;
}
return m_childItems.at(nIndex);
}
void TreeViewItem::appendChild(TreeViewItem* pItem)
{
assert(NULL != pItem && pItem->m_pParent == this);
if (NULL != pItem)
{
m_childItems.append(pItem);
}
}
int TreeViewItem::childCount() const
{
return m_childItems.size();
}
int TreeViewItem::childIndex(const TreeViewItem* pItem) const
{
assert(NULL != pItem);
if (NULL == pItem || m_childItems.isEmpty())
{
return -1;
}
QList
if (pos != m_childItems.end())
{
return pos - m_childItems.begin();
}
else
{
return -1;
}
}
bool TreeViewItem::removeChild(int nIndex)
{
if (nIndex < 0 || nIndex >= childCount())
{
return false;
}
TreeViewItem* pItem = child(nIndex);
if (NULL == pItem)
{
return false;
}
if (NULL != pItem->m_pDataInfo)
{
if (NULL != m_pDataInfo)
{
int nPos = m_pDataInfo->childExists(pItem->m_pDataInfo);
if (nPos >= 0 && nPos < m_pDataInfo->childCount())
{
m_pDataInfo->m_ChildList.removeAt(nPos);
}
}
delete pItem->m_pDataInfo;
pItem->m_pDataInfo = NULL;
}
delete pItem;
pItem = NULL;
m_childItems.removeAt(nIndex);
return true;
}
QVariant TreeViewItem::data(int nCol, int role /*= Qt::DisplayRole*/)
{
assert(NULL != m_pDataInfo);
assert(0 <= nCol && nCol <= 3);
if (NULL == m_pDataInfo)
{
return QVariant();
}
else if (Qt::TextAlignmentRole == role)
{
return int(Qt::AlignLeft);
}
else if (Qt::DisplayRole == role)
{
switch (nCol)
{
case 0: // get show name
return m_pDataInfo->m_TreeItmeName;
break;
}
}
return QVariant();
}
bool TreeViewItem::setData(int nCol, QVariant val, int role /*= Qt::EditRole*/)
{
}
int TreeViewItem::row() const
{
if (NULL == m_pParent)
{
return 0;
}
else
{
return m_pParent->m_childItems.indexOf(const_cast
}
}
Qt::ItemFlags TreeViewItem::flags(int nCol) const
{
if (NULL == m_pDataInfo)
{
return Qt::NoItemFlags;
}
if (1 == nCol)
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
}
else
{
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
}
}
TreeViewDataInfo* TreeViewItem::DataInfo() const
{
return m_pDataInfo;
}
bool TreeViewItem::swapChild(int nFirst, int nSecond)
{
assert(0 <= nFirst && nFirst < childCount());
assert(0 <= nSecond && nSecond < childCount());
if (nFirst < 0 || nFirst >= childCount()
|| nSecond < 0 || nSecond >= childCount())
{
return false;
}
m_childItems.swap(nFirst, nSecond);
if (NULL != m_pDataInfo
&& m_pDataInfo->m_ChildList.size() > nFirst
&& m_pDataInfo->m_ChildList.size() > nSecond)
{
m_pDataInfo->m_ChildList.swap(nFirst, nSecond);
}
return true;
}
(3)数据的model实现
ComboxTreeModel::ComboxTreeModel(QObject* parent /*= NULL*/)
{
m_pForRoot = new TreeViewDataInfo();
m_pRootItem = new TreeViewItem(m_pForRoot);
}
ComboxTreeModel::~ComboxTreeModel()
{
}
void ComboxTreeModel::updataModelTree(TreeViewDataInfoList MapList)
{
beginResetModel();
m_mapInfos = MapList;
if (m_mapInfos.isEmpty())
{
return;
}
if (NULL != m_pForRoot)
{
delete m_pForRoot;
m_pForRoot = NULL;
}
if (NULL != m_pRootItem)
{
delete m_pRootItem;
m_pRootItem = NULL;
}
bool bHasFind = false;
m_pForRoot = new TreeViewDataInfo();
m_pRootItem = new TreeViewItem(m_pForRoot);
assert(NULL != m_pRootItem);
//更新树里的数据,重新创建树的Itme项
for (int i = 0; i < m_mapInfos.size(); i++)
{
TreeViewDataInfo* pMap = m_mapInfos.at(i);
assert(NULL != pMap);
if (NULL != pMap->m_pParentInfo)
{
continue;
}
appendItem(pMap, m_pRootItem);
}
endResetModel();
}
TreeViewItem* ComboxTreeModel::itemFromIndex(QModelIndex index) const
{
if (!index.isValid())
{
return m_pRootItem;
}
else
{
return static_cast
}
}
int ComboxTreeModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const
{
if (parent.column() > 0)
{
return 0;
}
TreeViewItem* pParent = itemFromIndex(parent);
assert(NULL != pParent);
if (NULL != pParent)
{
return pParent->childCount();
}
else
{
return 0;
}
}
QModelIndex ComboxTreeModel::index(int row, int column, const QModelIndex &parent /*= QModelIndex()*/) const
{
assert(NULL != m_pRootItem);
if (!hasIndex(row, column, parent))
{
return QModelIndex();
}
TreeViewItem* pParentItem = itemFromIndex(parent);
assert(NULL != pParentItem);
if (NULL != pParentItem)
{
TreeViewItem* pItem = pParentItem->child(row);
QModelIndex oCreateIndex = createIndex(row, 0, pItem);
return oCreateIndex;
}
return QModelIndex();
}
QModelIndex ComboxTreeModel::parent(const QModelIndex &child) const
{
TreeViewItem* pItem = itemFromIndex(child);
assert(NULL != pItem);
TreeViewItem* pParentItem = pItem->parent();
if (NULL == pParentItem)
{
return QModelIndex();
}
else if (pParentItem == m_pRootItem)
{
return QModelIndex();
}
else
{
QModelIndex oCreateIndex = createIndex(pParentItem->row(), 0, pParentItem);
return oCreateIndex;
}
}
QVariant ComboxTreeModel::data(const QModelIndex &index, int role /*= Qt::DisplayRole*/) const
{
if (!index.isValid())
{
return QVariant();
}
TreeViewItem* pItem = static_cast
assert(NULL != pItem);
if (NULL != pItem)
{
return bulidData(pItem, index.column(), role);
}
else
{
return QVariant();
}
}
Qt::ItemFlags ComboxTreeModel::flags(const QModelIndex &index) const
{
TreeViewItem* pItem = itemFromIndex(index);
assert(NULL != pItem);
if (NULL != pItem)
{
return pItem->flags(index.column());
}
else
{
return Qt::NoItemFlags;
}
}
TreeViewItem* ComboxTreeModel::appendItem(TreeViewDataInfo* pDataInfo, TreeViewItem* pParentItem)
{
assert(NULL != pDataInfo && NULL != pParentItem);
if (NULL == pDataInfo || NULL == pParentItem)
{
return NULL;
}
//增加Item项
TreeViewItem* pItem = new TreeViewItem(pDataInfo, pParentItem);
assert(NULL != pItem);
if (NULL == pItem)
{
return NULL;
}
pParentItem->appendChild(pItem);
if (!pDataInfo->m_ChildList.isEmpty())
{
for (int i = 0; i < pDataInfo->m_ChildList.size(); i++)
{
TreeViewDataInfo* pChildMap = pDataInfo->m_ChildList.at(i);
assert(NULL != pChildMap);
if (NULL != pChildMap)
{
//树里不断增加子树
appendItem(pChildMap, pItem);
}
}
}
return pItem;
}
QVariant ComboxTreeModel::bulidData(TreeViewItem* pItem, int nCol, int role /*= Qt::DisplayRole*/) const
{
assert(NULL != pItem->DataInfo());
QString strShowName("");
if (NULL == pItem->DataInfo())
{
return QVariant();
}
else if (Qt::TextAlignmentRole == role)
{
return QVariant(Qt::AlignVCenter | Qt::AlignLeft);
}
else if (Qt::DisplayRole == role)
{
switch (nCol)
{
case 0:
strShowName = pItem->DataInfo()->m_TreeItmeName;
return strShowName;
default:
break;
}
}
return QVariant();
}
(4)窗体类的实现
TestDialog::TestDialog(QWidget* parent):QDialog(parent) //半自动化释放内存
{
initUI();
}
TestDialog::~TestDialog()
{
}
void TestDialog::refreshModelData(TreeViewDataInfoList DataList)
{
if (m_pTreeModel == nullptr || m_pTreeView == nullptr)
return;
m_pTreeModel->updataModelTree(DataList); //根据新的数据更新combox下的下拉树
m_pTreeView->expandAll(); //全部展开
setDefaultSelectItem(); //设置默认选中项
}
void TestDialog::setDefaultSelectItem(QString strItemName)
{
QAbstractItemModel *model = m_pCombox->view()->model();
QModelIndexList Items = model->match(model->index(0, 0), Qt::DisplayRole, QVariant::fromValue(strItemName), 2, Qt::MatchRecursive);
//这种做法解决combox中存在TreeView视图时刷洗设置二级以下节点为当前默认显示项Index无法显示正确信息的问题。
//如果需要将 子树下的第二 第三级等的子树设置为默认选项,需要这样子设置
if (Items.size() > 0)
{
for (QModelIndex m_oRightIndex : Items)
{
m_pCombox->setRootModelIndex(m_oRightIndex.parent());
m_pCombox->setModelColumn(m_oRightIndex.column());
m_pCombox->setCurrentIndex(m_oRightIndex.row());
m_pCombox->setRootModelIndex(QModelIndex());
m_pCombox->view()->setCurrentIndex(m_oRightIndex);
}
}
}
void TestDialog::initUI()
{
QHBoxLayout* pLayOut = new QHBoxLayout;
pLayOut->setContentsMargins(16, 10, 16, 10); //设置布局左右顶底距离的位置
m_pCombox = new QComboBox(this);
m_pTreeModel = new ComboxTreeModel();
m_pTreeView = new QTreeView(m_pCombox);
m_pTreeView->setHeaderHidden(true);
m_pTreeView->header()->hide(); //不显示头的行列
m_pTreeView->header()->hideSection(0);
pLayOut->addWidget(m_pCombox);
m_pCombox->setModel(m_pTreeModel); //将model设入树combox中
m_pCombox->setView(m_pTreeView); //将treeView设入combox中
this->setLayout(pLayOut); //将布局加入到窗体中
}