(处理复杂的树形结构)
树型控件
QStringListModel 用于存储简单的QString列表。
QStandardItemModel 管理复杂的树型结构数据项,每项都可以包含任意数据。
QDirModel提供本地文件系统中的文件与目录信息。
QSqlQueryModel,QSqlTableModel,QSqlRelationTableModel用来访问数据库。
自定义model:
可以处理庞大的数据,和增加特殊功能
(处理较为简单的树形结构)
使用QTreeWidgetItem类添加或设置项目
常用方法:
insertTopLevelItems() //在视图的顶层索引中引入项目的列表
expandAll() //展开所有节点的树形节点
invisibleRootItem() //返回树形控件中不可见的根选项(Root Item)
selectionItems() //返回所有选定的非隐藏项目的列表内
widgettree.h
#ifndef WIDGETTREE_H
#define WIDGETTREE_H
#include
#include
#include
#include "qctreewidget.h"
#include "qctreeview.h"
#include "qcmtreeview.h"
#include "typedef.h"
typedef struct CUSTOM_TREE_DATA_T
{
QString sDevno;
QString sName;
int number;
}CUSTOM_TREE_DATA;
typedef QHash QHashTestDev;
typedef QHash::iterator QHashTestDevIterator;
namespace Ui {
class WidgetTree;
}
class WidgetTree : public QWidget
{
Q_OBJECT
public:
explicit WidgetTree(QWidget *parent = nullptr);
~WidgetTree();
//初始化自定义的QTreeWidget
void initCustomTreeWidget();
//初始化自定义的QTreeView
void initCustomTreeView();
//初始化自定义model的QTreeView
void initCustomModelTreeView();
//初始化数据
void initTestDevHash();
QVector initData();
signals:
void sig_UpdateTreeWidget();
void sig_UpdateTreeView();
public slots:
//接收菜单栏操作信号
void on_refreshOne(QTreeWidgetItem* item);
void on_refreshAll();
void on_devOperate(QString devno);
void on_devSelectItem(QString devno, int nTreeMode);
void on_refreshOne(QStandardItem* item);
void on_devOperate(QStandardItem* item);
void on_devSelectItem(QStandardItem* item, int nTreeMode);
//更新自定义数据
void on_UpdateTreeWidget();
void on_UpdateTreeView();
protected:
void changeEvent(QEvent* event);
private slots:
void on_pushButton_Get2_clicked();
void on_pushButton_Get_clicked();
private:
void retranslateUi();
private:
QMutex m_lock;
//树数据存储
QHashTestDev m_testDevHash;
private:
Ui::WidgetTree *ui;
};
#endif // WIDGETTREE_H
widgettree.cpp
#include "widgettree.h"
#include "ui_widgettree.h"
#include "commondef.h"
#include
#include
#include
#include
WidgetTree::WidgetTree(QWidget *parent) :
QWidget(parent),
ui(new Ui::WidgetTree)
{
ui->setupUi(this);
retranslateUi();
initCustomTreeWidget();
initCustomTreeView();
initTestDevHash();
initCustomModelTreeView();
connect(this, SIGNAL(sig_UpdateTreeWidget()), this, SLOT(on_UpdateTreeWidget()));
connect(this, SIGNAL(sig_UpdateTreeView()), this, SLOT(on_UpdateTreeView()));
}
WidgetTree::~WidgetTree()
{
delete ui;
}
/*************************
* QTreeWidget-初始化
* ***********************/
void WidgetTree::initCustomTreeWidget()
{
connect(ui->treeWidget, SIGNAL(sig_refreshOne(QTreeWidgetItem*)), this, SLOT(on_refreshOne(QTreeWidgetItem*)));
connect(ui->treeWidget, SIGNAL(sig_refreshAll()), this, SLOT(on_refreshAll()));
connect(ui->treeWidget, SIGNAL(sig_devOperate(QString)), this, SLOT(on_devOperate(QString)));
connect(ui->treeWidget, SIGNAL(sig_devSelectItem(QString, int)), this, SLOT(on_devSelectItem(QString, int)));
ui->treeWidget->setTreeMode(TREE_MODE_DEMO, true);
}
/*************************
* QTreeWidget-创建节点
* ***********************/
void WidgetTree::on_UpdateTreeWidget()
{
//QMutexLocker guard(&m_lock);
//1.创建节点列表
QList devTreeWiditems;
QStringList strList;
ui->treeWidget->clear();
QHashTestDevIterator i = m_testDevHash.begin();
for(; i != m_testDevHash.end(); ++i)
{
CUSTOM_TREE_DATA dev = i.value();
strList.clear();
strList << dev.sDevno;
//2.创建QTreeWidgetItem节点,并设置相关数据
QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget, strList);
item->setToolTip(0, strList.first());
//Qt::ItemIsSelectable表示可选的
//Qt::ItemIsUserCheckable项目上是否有复选框
//Qt::ItemIsEnabled 项目上是否没有被禁用(Enabled可用/Disabled禁用)
//Qt::ItemIsDragEnabled 是否可拖动
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable
| Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
item->setData(0, ROLE_DEVNO, dev.sDevno);
item->setData(0, ROLE_NAME, dev.sName);
item->setData(0, ROLE_NUMBER, dev.number);
for(int j = 0; j < 2; j++)
{
QStringList subStrList;
subStrList << QString("%1_%2").arg(dev.sDevno).arg(j);
//3.创建QTreeWidgetItem次级节点,并设置相关数据
QTreeWidgetItem* subItem = new QTreeWidgetItem(item, subStrList);
subItem->setData(0, Qt::WhatsThisRole, QVariant("subItem"));
subItem->setData(0, ROLE_SUB_DEVNO, QString("%1_%2").arg(dev.sDevno).arg(j));
//4.一级节点添加二级节点
item->addChild(subItem);
}
//5.节点列表添加一级节点
devTreeWiditems.push_back(item);
}
//6.统一添加顶层节点
ui->treeWidget->insertTopLevelItems(0, devTreeWiditems);
}
//
/*************************
* QTreeView-初始化
* ***********************/
void WidgetTree::initCustomTreeView()
{
connect(ui->treeView, SIGNAL(sig_refreshOne(QStandardItem*)), this, SLOT(on_refreshOne(QStandardItem*)));
connect(ui->treeView, SIGNAL(sig_refreshAll()), this, SLOT(on_refreshAll()));
connect(ui->treeView, SIGNAL(sig_devOperate(QStandardItem*)), this, SLOT(on_devOperate(QStandardItem*)));
connect(ui->treeView, SIGNAL(sig_devSelectItem(QStandardItem*, int)), this, SLOT(on_devSelectItem(QStandardItem*, int)));
ui->treeView->setTreeMode(TREE_VIEW_MODE_DEMO, true);
//隐藏表头
ui->treeView->setHeaderHidden(true);
//设置展开
//ui->treeView->expandAll();
}
/*************************
* QTreeView自定义模型-初始化
* ***********************/
void WidgetTree::initCustomModelTreeView()
{
QVector proList = initData();
QStringList headers;
headers << QStringLiteral("Name")
<< QStringLiteral("ID")
<< QStringLiteral("Persons")
<< QStringLiteral("Superior");
ui->treeView_2->setModelByHeader(headers);
TreeItem* root = ui->treeView_2->getModel()->root();
foreach (auto depNode, proList)
{
TreeItem* depItem = new TreeItem(root);
depItem->setPtr(depNode); // 保存数据指针
root->addChild(depItem);
foreach (auto subNode, depNode->subList)
{
TreeItem* subItem = new TreeItem(depItem);
subItem->setPtr(subNode); // 保存数据指针
depItem->addChild(subItem);
}
}
}
/*************************
* QTreeView-创建节点
* ***********************/
void WidgetTree::on_UpdateTreeView()
{
QStandardItem* pStandardItem = nullptr;
QStandardItem* pStandardChildItem = nullptr;
ui->treeView->getModel()->clear();
int row = 0;
QHashTestDevIterator i = m_testDevHash.begin();
for(; i != m_testDevHash.end(); ++i)
{
CUSTOM_TREE_DATA dev = i.value();
//1.创建一级复杂数据项节点
pStandardItem = new QStandardItem(dev.sDevno);
//2.使用QStandardItemModel添加一级复杂数据项节点
ui->treeView->getModel()->appendRow(pStandardItem);
pStandardItem->setData(-1, ROLE_PARENT);
pStandardItem->setData(dev.sDevno, ROLE_DEVNO);
pStandardItem->setData(dev.sName, ROLE_NAME);
//添加子节点
for(int j = 0; j < 2; j++)
{
//3.创建次级复杂数据项节点
pStandardChildItem = new QStandardItem(QString("%1_%2").arg(dev.sDevno).arg(j));
pStandardChildItem->setData(row, ROLE_PARENT);
pStandardChildItem->setData(QString("%1_%2").arg(dev.sName).arg(j), ROLE_NAME);
//4.一级复杂数据项节点添加次级复杂数据项节点
pStandardItem->appendRow(pStandardChildItem);
}
row++;
}
}
/*************************
* 填充数据
* ***********************/
void WidgetTree::initTestDevHash()
{
CUSTOM_TREE_DATA testDev[5];
testDev[0] = {"AAA", "192.168.1.100", 1};
testDev[1] = {"BBB", "192.168.1.101", 2};
testDev[2] = {"CCC", "192.168.1.102", 3};
testDev[3] = {"DDD", "192.168.1.103", 4};
testDev[4] = {"EEE", "192.168.1.104", 5};
for(int i = 0; i < 5; i++)
{
m_testDevHash.insert(testDev[i].sDevno, testDev[i]);
}
}
QVector WidgetTree::initData()
{
QFile file(":/Resource/Txt/default.txt");
file.open(QIODevice::ReadOnly);
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
QJsonObject obj = doc.object();
QJsonArray array = obj.value("nextLevel").toArray();
QVector depList;
for(int i = 0; i < array.size(); ++i)
{
QJsonObject subObject = array.at(i).toObject();
QJsonArray subArray = subObject.value("nextLevel").toArray();
Department *topDepartment = new Department();
topDepartment->id = subObject.value("id").toInt();
topDepartment->name = subObject.value("name").toString();
topDepartment->number = subObject.value("nnt").toInt();
topDepartment->preOrganizationName = subObject.value("preOrganizationName").toString();
//第二级
for(int i = 0; i < subArray.size(); ++i)
{
QJsonObject tempObj = subArray.at(i).toObject();
Department *subDepartment = new Department();
subDepartment->id = tempObj.value("id").toInt();
subDepartment->name = tempObj.value("name").toString();
subDepartment->number = tempObj.value("nnt").toInt();
subDepartment->preOrganizationName = tempObj.value("preOrganizationName").toString();
topDepartment->subList.append(subDepartment);
}
depList.append(topDepartment);
}
return depList;
}
void WidgetTree::on_pushButton_Get2_clicked()
{
emit sig_UpdateTreeWidget();
}
void WidgetTree::on_pushButton_Get_clicked()
{
emit sig_UpdateTreeView();
}
/*************************
* 菜单栏操作
* ***********************/
void WidgetTree::on_refreshOne(QTreeWidgetItem *item)
{
MY_DEBUG << "Refresh:" << item->data(0, ROLE_SUB_DEVNO).toString();
}
void WidgetTree::on_refreshAll()
{
MY_DEBUG << "Refresh all";
}
void WidgetTree::on_devOperate(QString devno)
{
MY_DEBUG << "devno" << devno;
}
void WidgetTree::on_devSelectItem(QString devno, int nTreeMode)
{
MY_DEBUG << "devno:" << devno << ", nTreeMode:" << nTreeMode;
}
void WidgetTree::on_refreshOne(QStandardItem *item)
{
MY_DEBUG << "item->data(ROLE_NAME):" << item->data(ROLE_NAME).toString();
}
void WidgetTree::on_devOperate(QStandardItem *item)
{
MY_DEBUG << "item->data(ROLE_NAME):" << item->data(ROLE_NAME).toString();
}
void WidgetTree::on_devSelectItem(QStandardItem *item, int nTreeMode)
{
MY_DEBUG << "item->data(ROLE_NAME):" << item->data(ROLE_NAME) << ", nTreeMode:" << nTreeMode;
}
/*************************
* 语言翻译
* ***********************/
void WidgetTree::changeEvent(QEvent *event)
{
switch(event->type())
{
case QEvent::LanguageChange:
retranslateUi();
break;
default:
QWidget::changeEvent(event);
}
}
void WidgetTree::retranslateUi()
{
ui->label->setText(tr("Use Tree View:"));
ui->label_2->setText(tr("Use Tree Widget:"));
ui->label_3->setText(tr("Use Tree View(Custom model):"));
}
qctreeview.h
#ifndef QCTREEVIEW_H
#define QCTREEVIEW_H
#include
#include
#include
#include
#include
enum TreeViewMode
{
TREE_VIEW_MODE_DEMO = 0,
TREE_VIEW_MODE_MAX
};
#define ROLE_DEVNO (Qt::UserRole)
#define ROLE_PARENT (Qt::UserRole+1)
#define ROLE_NAME (Qt::UserRole+2)
class QCTreeView : public QTreeView
{
Q_OBJECT
public:
explicit QCTreeView(QWidget *parent = nullptr);
~QCTreeView() Q_DECL_OVERRIDE;
void setTreeMode(int nTreemode, bool bDrag);
void initMenu();
QStandardItemModel* getModel();
protected:
void changeEvent(QEvent* event) Q_DECL_OVERRIDE;
//鼠标事件
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; // first event.
//void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; // second
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
private:
void translateUI();
//tree mode
int m_nTreemode;
//Menu
QMenu *m_actMenu;
QAction *m_actDevRefresh;
QAction *m_actDevRefreshall;
QAction *m_actDevOperate;
//tree model
QStandardItemModel* m_pModel;
QPoint m_startpos;
signals:
//单个刷新
void sig_refreshOne(QStandardItem *item);
//全部刷新
void sig_refreshAll();
//操作
void sig_devOperate(QStandardItem *item);
//选中
void sig_devSelectItem(QStandardItem *item, int nMode);
public slots:
void on_showContextMenu(const QPoint& pos);
};
#endif // QCTREEVIEW_H
qctreeview.cpp
#include
#include
#include
#include "messagebox.h"
#include "qctreeview.h"
#include "commondef.h"
QCTreeView::QCTreeView(QWidget *parent)
: QTreeView(parent)
{
m_nTreemode = 0;
m_pModel = new QStandardItemModel(this);
setModel(m_pModel);
//在view内item支持拖和放
this->setDragDropMode(QTreeView::DragDrop);//NoDragDrop:不支持拖和放
//在view内item支持正常选择时,一次选择一项;可以通过拖动鼠标选择多项
this->setSelectionMode(QAbstractItemView::ExtendedSelection);
//双击禁止展开
this->setExpandsOnDoubleClick(false);
//初始化是禁止拖拽
this->setDragEnabled(false);
//设置列宽
//this->setColumnWidth(0, 320);
//设置最大尺寸宽度
//this->setMaximumWidth(320);
initMenu();
}
QCTreeView::~QCTreeView()
{
SAFE_FREE(m_actDevRefresh);
SAFE_FREE(m_actDevRefreshall);
SAFE_FREE(m_actDevOperate);
SAFE_FREE(m_actMenu);
SAFE_FREE(m_pModel);
}
void QCTreeView::setTreeMode(int nTreemode, bool bDrag)
{
m_nTreemode = nTreemode;
this->setDragEnabled(bDrag);
}
void QCTreeView::initMenu()
{
m_actMenu = new QMenu(this);
m_actMenu->setStyleSheet("border:1px solid #4d738b;");
m_actDevRefresh = new QAction("Refresh", this);
m_actDevRefreshall = new QAction("Refresh all", this);
m_actDevOperate = new QAction("Operate", this);
connect(m_actDevRefresh, &QAction::triggered, [this]()
{
QModelIndex curIndex = this->currentIndex();
int row = curIndex.row();
int column = curIndex.column();
if(-1 == row || -1 == column)
{
return;
}
QStandardItem *curItem;
int parentRow = curIndex.data(ROLE_PARENT).toInt();
if(-1 == parentRow)
{
curItem = m_pModel->item(row, column);
}
else
{
QStandardItem *parentItem = m_pModel->item(parentRow, column);
curItem = parentItem->child(row, column);
}
if(curItem)
{
emit this->sig_refreshOne(curItem);
}
});
connect(m_actDevRefreshall, &QAction::triggered, [this]()
{
emit sig_refreshAll();
});
connect(m_actDevOperate, &QAction::triggered, [this]()
{
QModelIndex curIndex = this->currentIndex();
int row = curIndex.row();
int column = curIndex.column();
if(-1 == row || -1 == column)
{
return;
}
QStandardItem *curItem;
int parentRow = curIndex.data(ROLE_PARENT).toInt();
if(-1 == parentRow)
{
curItem = m_pModel->item(row, column);
}
else
{
QStandardItem *parentItem = m_pModel->item(parentRow, column);
curItem = parentItem->child(row, column);
}
if(curItem)
{
emit this->sig_devOperate(curItem);
}
});
//设置菜单属性方法 右键菜单
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint& )),
this, SLOT(on_showContextMenu(const QPoint&)));
}
QStandardItemModel *QCTreeView::getModel()
{
return m_pModel;
}
void QCTreeView::changeEvent(QEvent *event)
{
switch(event->type())
{
case QEvent::LanguageChange:
translateUI();
break;
default:
QWidget::changeEvent(event);
}
}
void QCTreeView::translateUI()
{
m_actDevRefresh->setText(QObject::tr("Refresh"));
m_actDevRefreshall->setText(QObject::tr("Refresh All"));
m_actDevOperate->setText(QObject::tr("Play"));
}
void QCTreeView::on_showContextMenu(const QPoint &pos)
{
QModelIndex curIndex = indexAt(pos);
int row = curIndex.row();
int column = curIndex.column();
m_actMenu->clear();
if(-1 == row || -1 == column)
{
m_actMenu->addAction(m_actDevRefreshall);
}
else
{
m_actMenu->addAction(m_actDevRefresh);
m_actMenu->addAction(m_actDevOperate);
}
m_actMenu->exec(mapToGlobal(pos));
}
void QCTreeView::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
m_startpos = event->pos();
}
QModelIndex curIndex = indexAt(event->pos());
if(m_nTreemode == TREE_VIEW_MODE_DEMO)
{
int row = curIndex.row();
int column = curIndex.column();
if(-1 == row || -1 == column)
{
return;
}
QStandardItem *curItem;
int parentRow = curIndex.data(ROLE_PARENT).toInt();
if(-1 == parentRow)
{
curItem = m_pModel->item(row, column);
}
else
{
QStandardItem *parentItem = m_pModel->item(parentRow, column);
curItem = parentItem->child(row, column);
}
if(curItem)
{
emit sig_devSelectItem(curItem, m_nTreemode);
}
}
QTreeView::mousePressEvent(event);
}
void QCTreeView::mouseReleaseEvent(QMouseEvent *event)
{
QTreeView::mouseReleaseEvent(event);
}
void QCTreeView::mouseDoubleClickEvent(QMouseEvent *event)
{
QTreeView::mouseDoubleClickEvent(event);
}
qctreewidget.h
#ifndef QCTREEWIDGET_H
#define QCTREEWIDGET_H
#include
#include
#include
#include
enum TreeWidgetMode
{
TREE_MODE_DEMO = 0,
TREE_MODE_MAX
};
#define ROLE_DEVNO (Qt::UserRole)
#define ROLE_NAME (Qt::UserRole+1)
#define ROLE_NUMBER (Qt::UserRole+2)
#define ROLE_SUB_DEVNO (Qt::UserRole+3)
class QCTreeWidget : public QTreeWidget
{
Q_OBJECT
public:
explicit QCTreeWidget(QWidget *parent = nullptr);
~QCTreeWidget() Q_DECL_OVERRIDE;
void setTreeMode(int nTreemode, bool bDrag);
void initMenu();
protected:
void changeEvent(QEvent* event) Q_DECL_OVERRIDE;
//右菜单事件
void contextMenuEvent(QContextMenuEvent *event) Q_DECL_OVERRIDE;
//拖拽事件
void startDrag(Qt::DropActions Actions) Q_DECL_OVERRIDE;
void dragMoveEvent(QDragMoveEvent *event) Q_DECL_OVERRIDE;
void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE;
//鼠标事件
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; // first event.
void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; // second
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
private:
void translateUI();
//tree mode
int m_nTreemode;
//Menu
QMenu *m_actMenu;
QAction *m_actDevRefresh;
QAction *m_actDevRefreshall;
QAction *m_actDevOperate;
//tree item
QTreeWidgetItem *m_pItem;
QPoint m_startpos;
QTreeWidgetItem *m_curDragItem;
signals:
//单个刷新
void sig_refreshOne(QTreeWidgetItem *item);
//全部刷新
void sig_refreshAll();
//操作
void sig_devOperate(QString sMac);
//选中
void sig_devSelectItem(QString sMac, int nMode);
};
#endif // QCTREEWIDGET_H
qctreewidget.cpp
#include
#include
#include
#include "messagebox.h"
#include "qctreewidget.h"
#include "commondef.h"
QCTreeWidget::QCTreeWidget(QWidget *parent)
: QTreeWidget(parent)
{
m_nTreemode = 0;
this->m_pItem = nullptr;
//在view内item支持拖和放
this->setDragDropMode(QTreeWidget::DragDrop);//NoDragDrop:不支持拖和放
//在view内item支持正常选择时,一次选择一项;可以通过拖动鼠标选择多项
this->setSelectionMode(QAbstractItemView::ExtendedSelection);
//双击禁止展开
this->setExpandsOnDoubleClick(false);
//初始化是禁止拖拽
this->setDragEnabled(false);
//设置列宽
//this->setColumnWidth(0, 320);
//设置最大尺寸宽度
//this->setMaximumWidth(320);
initMenu();
}
QCTreeWidget::~QCTreeWidget()
{
SAFE_FREE(m_actDevRefresh);
SAFE_FREE(m_actDevRefreshall);
SAFE_FREE(m_actDevOperate);
SAFE_FREE(m_actMenu);
}
void QCTreeWidget::setTreeMode(int nTreemode, bool bDrag)
{
m_nTreemode = nTreemode;
this->setDragEnabled(bDrag);
}
void QCTreeWidget::initMenu()
{
m_actMenu = new QMenu(this);
m_actMenu->setStyleSheet("border:1px solid #4d738b;");
m_actDevRefresh = new QAction("Refresh", this);
m_actDevRefreshall = new QAction("Refresh all", this);
m_actDevOperate = new QAction("Operate", this);
connect(m_actDevRefresh, &QAction::triggered, [this]()
{
QTreeWidgetItem *item = currentItem();
if(item)
{
emit this->sig_refreshOne(item);
}
});
connect(m_actDevRefreshall, &QAction::triggered, [this]()
{
emit sig_refreshAll();
});
connect(m_actDevOperate, &QAction::triggered, [this]()
{
QTreeWidgetItem *item = currentItem();
if(item)
{
QString sKey;
sKey = item->data(0, ROLE_SUB_DEVNO).toString();
emit this->sig_devOperate(sKey);
}
});
}
void QCTreeWidget::changeEvent(QEvent *event)
{
switch(event->type())
{
case QEvent::LanguageChange:
translateUI();
break;
default:
QWidget::changeEvent(event);
}
}
void QCTreeWidget::translateUI()
{
m_actDevRefresh->setText(QObject::tr("Refresh"));
m_actDevRefreshall->setText(QObject::tr("Refresh All"));
m_actDevOperate->setText(QObject::tr("Play"));
}
void QCTreeWidget::contextMenuEvent(QContextMenuEvent *event)
{
m_actMenu->clear();
QList Item_list = this->selectedItems();
if (Item_list.size() > 1)
{
m_actMenu->addAction(m_actDevOperate);
m_actMenu->exec(QCursor::pos());
return;
}
QPoint pos = event->pos();
QTreeWidgetItem *curitem = itemAt(pos);
if(curitem) //右键对象菜单
{
switch(m_nTreemode)
{
case TREE_MODE_DEMO:
m_actMenu->addAction(m_actDevOperate);
m_actMenu->addAction(m_actDevRefresh);
m_actMenu->exec(QCursor::pos());
break;
}
//m_actMenu->exec(QCursor::pos());//空菜单会导致右键卡一下
}
else //右键空白菜单
{
bool isShowMenu = true;
switch(m_nTreemode)
{
// 禁止视频的一键播放功能
case TREE_MODE_DEMO:
m_actMenu->addAction(m_actDevRefreshall);
break;
default:
isShowMenu = false;
break;
}
if(isShowMenu)
{
m_actMenu->exec(QCursor::pos());
}
}
event->accept();
}
void QCTreeWidget::startDrag(Qt::DropActions Actions)
{
m_curDragItem = currentItem();
if(m_nTreemode == TREE_MODE_DEMO)
{
QTreeWidget::startDrag(Actions);
}
else
{
if(m_curDragItem->parent() != nullptr) //目录不允许拖动
{
QTreeWidget::startDrag(Actions);
}
}
}
void QCTreeWidget::dragMoveEvent(QDragMoveEvent *event)
{
if(m_nTreemode == TREE_MODE_DEMO)
{
QCTreeWidget *src = qobject_cast(event->source());
if(src && src != this) // 移动到其他地盘
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
else // 不允许自己拖动到自己地盘
{
event->ignore();
}
}
else
{
QCTreeWidget *src = qobject_cast(event->source());
if(src && src != this) // 移动到其他地盘,触发移动效果
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
else // 自己地盘允许自由拖放
{
QTreeWidget::dragMoveEvent(event);
}
}
}
void QCTreeWidget::dropEvent(QDropEvent *event)
{
if(m_nTreemode == TREE_MODE_DEMO)
{
m_pItem = nullptr;
QCTreeWidget *src = qobject_cast(event->source());
if(src && src != this) // 移动到其他地盘
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
else // 不允许自己拖动到自己地盘
{
event->ignore();
}
}
else
{
QTreeWidgetItem *dst = this->itemAt(event->pos()); //当前位置的item
if(dst == nullptr || dst->parent() != nullptr)//如果不是目录,忽略
{
event->ignore();
return;
}
if(dst == m_curDragItem->parent() || dynamic_cast(dst) == dynamic_cast(this))//如果是相同目录,忽略
{
event->ignore();
return;
}
}
}
void QCTreeWidget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
m_startpos = event->pos();
}
//增加选中状态更新
m_pItem = this->itemAt(event->pos());
if(m_nTreemode == TREE_MODE_DEMO)
{
if(m_pItem && m_pItem->parent() == nullptr)
{
QString sMac = m_pItem->data(0, ROLE_DEVNO).toString();
MY_DEBUG << "TREE_MODE_DEMO sMac:" << sMac;
emit sig_devSelectItem(sMac, m_nTreemode);
}
}
else
{
if(m_pItem && m_pItem->parent() != nullptr)
{
QString sMac = m_pItem->data(0, ROLE_DEVNO).toString();
MY_DEBUG << "Not TREE_MODE_DEMO sMac:" << sMac;
emit sig_devSelectItem(sMac, m_nTreemode);
}
}
QTreeWidget::mousePressEvent(event);
}
void QCTreeWidget::mouseMoveEvent(QMouseEvent *event)
{
if(this->dragEnabled())
{
QTreeWidgetItem *item = currentItem();
if(item)
{
if(item->flags() & Qt::ItemIsDragEnabled)
{
if(event->buttons() & Qt::LeftButton) //确保按住左键移动.
{
if(selectedItems().size() > 1)//多选
{
return;
}
int ndis = (event->pos() - m_startpos).manhattanLength();
if(ndis > QApplication::startDragDistance())//只有这个长度大于默认的距离,才会被系统认为是形成拖拽的操作.
{
QTreeWidgetItem *item = this->m_pItem;
if(item == nullptr)
{
return;
}
QMimeData *mimeData = new QMimeData;
if(item->data(0, Qt::WhatsThisRole).toString() == QVariant("subItem"))
{
QString sDevno = item->data(0, ROLE_DEVNO).toString();
mimeData->setProperty("Devno", QVariant(sDevno));
}
else
{
return;
}
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setPixmap(item->icon(0).pixmap(28));
if(drag->exec(Qt::MoveAction) == Qt::MoveAction){}
}
}
}
}
}
}
void QCTreeWidget::mouseReleaseEvent(QMouseEvent *event)
{
QTreeWidget::mouseReleaseEvent(event);
}
void QCTreeWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
QTreeWidget::mouseDoubleClickEvent(event);
}
treeitem.h
#ifndef TREEITEM_H
#define TREEITEM_H
#include
class TreeItem
{
public:
enum Type
{
UNKNOWN = -1,
PROVINCE,
PERSON
};
explicit TreeItem(TreeItem *parent = nullptr);
~TreeItem();
void addChild(TreeItem *item);
void removeChildren();
TreeItem *child(int row) { return m_childrenList.value(row); }
TreeItem *parent() { return m_pParent; }
int childCount() const { return m_childrenList.count(); }
QVariant data(int column) const;
//设置、获取节点存的数据指针
void setPtr(void* p) { m_ptr = p; }
void* ptr() const { return m_ptr; }
// 保存该节点是其父节点的第几个子节点,查询优化所用
void setRow(int row) { m_nRow = row; }
//返回本节点位于父节点下第几个子节点
int row() const { return m_nRow; }
//类型
Type getType() const { return m_nType; }
void setType(const Type &value) { m_nType = value; }
private:
QList m_childrenList; // 子节点
TreeItem *m_pParent; // 父节点
Type m_nType; // 此节点保存的数据类型
void* m_ptr; // 存储数据的指针
int m_nRow; // 此item位于父节点中第几个
};
#endif // TREEITEM_H
treeitem.cpp
#include "treeitem.h"
#include "typedef.h"
TreeItem::TreeItem(TreeItem *parent)
: m_pParent(parent),
m_nType(UNKNOWN),
m_ptr(nullptr),
m_nRow(-1)
{
}
TreeItem::~TreeItem()
{
removeChildren();
}
// 在本节点下添加子节点
void TreeItem::addChild(TreeItem *item)
{
item->setRow(m_childrenList.size());
m_childrenList.append(item);
}
// 清空所有子节点
void TreeItem::removeChildren()
{
qDeleteAll(m_childrenList);
m_childrenList.clear();
}
// 获取本节点第column列的数据
QVariant TreeItem::data(int column) const
{
Department *department = (Department*)m_ptr;
switch (column) {
case COLUMN_NAME: return department->name;
case COLUMN_ID: return department->id;
case COLUMN_NUM: return department->number;
case COLUMN_OrganizationName: return department->preOrganizationName;
default:return QVariant();
}
return QVariant();
}
treemodel.h
#ifndef TREEMODEL_H
#define TREEMODEL_H
#include
class TreeItem;
//自定义模型
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit TreeModel(const QStringList& headers, QObject *parent = nullptr);
~TreeModel() override;
//根节点
TreeItem *root();
//获取表头数据
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
//获取index.row行,index.column列数据
QVariant data(const QModelIndex &index, int role) const override;
//在parent节点下,第row行,第column列位置上创建索引
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
//创建index的父索引
QModelIndex parent(const QModelIndex &index) const override;
//获取索引parent下有多少行
int rowCount(const QModelIndex &parent) const override;
//返回索引parent下有多少列
int columnCount(const QModelIndex &parent) const override;
private:
TreeItem *itemFromIndex(const QModelIndex &index) const;
private:
QStringList m_pHeaders;
TreeItem* m_pRootItem;
};
#endif // TREEMODEL_H
treemodel.cpp
#include "treemodel.h"
#include "treeitem.h"
#include "commondef.h"
TreeModel::TreeModel(const QStringList& headers, QObject *parent)
: QAbstractItemModel(parent)
{
m_pHeaders = headers;
m_pRootItem = new TreeItem();
}
TreeModel::~TreeModel()
{
delete m_pRootItem;
}
TreeItem *TreeModel::itemFromIndex(const QModelIndex &index) const
{
if (index.isValid())
{
TreeItem *item = static_cast(index.internalPointer());
return item;
}
return m_pRootItem;
}
TreeItem *TreeModel::root()
{
return m_pRootItem;
}
// 获取表头数据
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,int role) const
{
if (orientation == Qt::Horizontal)
{
if(role == Qt::DisplayRole)
{
return m_pHeaders.at(section);
}
}
return QVariant();
}
// 获取index.row行,index.column列数据
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
TreeItem *item = itemFromIndex(index);
if (role == Qt::DisplayRole)
{
return item->data(index.column());
}
return QVariant();
}
// 在parent节点下,第row行,第column列位置上创建索引
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeItem *parentItem = itemFromIndex(parent);
TreeItem *item = parentItem->child(row);
if (item)
return createIndex(row, column, item);
else
return QModelIndex();
}
// 创建index的父索引
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
TreeItem *item = itemFromIndex(index);
TreeItem *parentItem = item->parent();
if (parentItem == m_pRootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
// 获取索引parent下有多少行
int TreeModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0)
return 0;
TreeItem* item = itemFromIndex(parent);
return item->childCount();
}
// 返回索引parent下有多少列
int TreeModel::columnCount(const QModelIndex &parent) const
{
return m_pHeaders.size();
}
typedef.h
#ifndef TYPEDEF_H
#define TYPEDEF_H
#include
// department信息
typedef struct Department_t{
QString name; // 部门名称
int id; // 部门id号
int number; // 部门人数
QString preOrganizationName; // 上级组织名
Department_t()
{
id = 0;
number = 0;
}
QVector subList;
} Department;
// 树列号
enum COLUMN
{
COLUMN_NAME = 0,
COLUMN_ID,
COLUMN_NUM,
COLUMN_OrganizationName
};
#endif // TYPEDEF_H
https://download.csdn.net/download/linyibin_123/86512679