项目中代码
#include "treewidget.h"
#include "dataprocess.h"
#include "addsondialog.h"
#include "dialog.h"
#include "setconfdialog.h"
#include <QHeaderView>
#include <QVector>
#include <vector>
#include <algorithm>
#include <iostream>
// 必须加上此宏定义,不然报错,导致无法提取树中数据
Q_DECLARE_METATYPE(TypeData)
TreeWidget::TreeWidget(QTreeWidget *parent) : QTreeWidget(parent)
{
// 设置颜色
QString strStyleSheet = QString("QSplitter::handle { background-color: rgb(179, 179, 179); }") //分割线的颜色
+ QString("QSplitter {border: 2px solid green}");
this->setStyleSheet(strStyleSheet);
this->setColumnCount(1); // 设置列数
this->setHeaderLabel(tr("Vehicle")); // 设置标题
this->menu = new QMenu;
this->action1 = new QAction("设置当前菜单");
this->action2 = new QAction("删除");
this->action3 = new QAction("设置子菜单");
this->action4 = new QAction("添加子菜单");
this->action5 = new QAction("复制");
this->action6 = new QAction("粘贴");
this->action8 = new QAction("剪切");
this->menu->addAction(action1);
this->menu->addAction(action2);
this->menu->addAction(action3);
this->menu->addAction(action4);
this->menu->addAction(action8);
this->menu->addAction(action5);
this->menu->addAction(action6);
// 发送信号
connect(action1, &QAction::triggered, this, &TreeWidget::SetCarItem, Qt::UniqueConnection);
connect(action2, &QAction::triggered, this, &TreeWidget::DeleteCarItem, Qt::UniqueConnection);
connect(action3, &QAction::triggered, this, &TreeWidget::SetSonItem, Qt::UniqueConnection);
connect(action4, &QAction::triggered, this, &TreeWidget::AddSonItem, Qt::UniqueConnection);
connect(action5, &QAction::triggered, this, &TreeWidget::CopyItem, Qt::UniqueConnection);
connect(action6, &QAction::triggered, this, &TreeWidget::PasteItem, Qt::UniqueConnection);
connect(action8, &QAction::triggered, this, &TreeWidget::ShearItem, Qt::UniqueConnection);
}
//初始化界面
void TreeWidget::InitUI()
{
QVector<QString> vecCarName;
this->mysqlData->GetCarIndex(vecCarName);
// 将电控制系统放入树中
for (int i = 0; i < vecCarName.size(); i++) {
QTreeWidgetItem *widgetItem = new QTreeWidgetItem();
widgetItem->setText(0, vecCarName[i]);
// 树根
this->addTopLevelItem(widgetItem);
}
// 双击展开事件 showSonItem槽函数触发
connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(ShowSonItem(QTreeWidgetItem*,int)));
//connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(ShowMenuData(QTreeWidgetItem*,int)));
// 点击事件,显示右边参数,触发ShowMenuData槽函数
connect(this, SIGNAL(itemPressed(QTreeWidgetItem*,int)), this, SLOT(ShowMenuData(QTreeWidgetItem*,int)));
this->setStyle(QStyleFactory::create("windows")); // 将树加上虚线
//this->scrollToTop(); //让滚动条滚动到最顶部
// 水平滑动条
this->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
this->header()->setStretchLastSection(false);
this->expandAll(); //结点全部展开
}
// 添加车系Item
void TreeWidget::AddCarItem(QTreeWidgetItem*& item, TypeData& typeData)
{
QString strTitle = "";
// 查数据库得到title
this->mysqlData->GetTMenuTitle(typeData.carid, typeData.textid, strTitle);
QTreeWidgetItem *widgetItem1_1 = new QTreeWidgetItem();
widgetItem1_1->setText(0, strTitle);
widgetItem1_1->setData(0, Qt::UserRole, QVariant::fromValue(typeData));
item->addChild(widgetItem1_1);
}
// 双击事件的槽函数
void TreeWidget::ShowSonItem(QTreeWidgetItem * item, int column)
{
if (item != nullptr) {
if (qApp->mouseButtons() == Qt::LeftButton) { // 左键
// 如果已经添加了子节点就无需再添加,删除子节点起到刷新的作用
DataProcess::DeleteSonItem(item);
// 节点深度
int count = 0;
QTreeWidgetItem* itemCurrent = item;
// 求出树的深度
this->LengthTreeItem(count, itemCurrent);
// 添加ecu
if (count == 0) { // 第0层
// 添加第0深度的内容
this->AddZeroItem(item);
} else if (count >= 1) { // 第一层
this->AddOneItem(item);
}
} else if (qApp->mouseButtons() == Qt::RightButton) { // 右键
//qDebug() << " double rightbutton";
}
}
}
// 添加第0深度的内容
void TreeWidget::AddZeroItem(QTreeWidgetItem*& item)
{
// 那个根目录下,求出根的名字
QString strTitle = item->text(0);
QVector<QString> vecCarId;
this->mysqlData->GetCarIndex(strTitle, vecCarId);
// 查找TypeData表
for (int i = 0; i < vecCarId.size(); i++) {
QString strCarIndex = vecCarId[i].mid(2, vecCarId[i].size()-2);
QVector<QString> vecTypeData;
// 查找第0个及为根车系名
this->mysqlData->GetVecTypeData(strCarIndex, "0", vecTypeData);
if (vecTypeData.size() == 0) {
continue;
}
TypeData typeData;
typeData.GetVec(vecTypeData);
this->AddCarItem(item, typeData);
}
}
// 添加第一深度的内容
void TreeWidget::AddOneItem(QTreeWidgetItem*& item)
{
TypeData typeData = item->data(0, Qt::UserRole).value<TypeData>();
QString carId = typeData.carid;
QString strId = typeData.id;
// 查询DataConf表得到子目录
QVector<DataConf> vecData = this->mysqlData->GetDataConf(carId, strId);
//升序排序
std::sort(vecData.begin(), vecData.end(), std::less<DataConf>());
// 没有子节点
if (vecData.size() == 0) {
return;
}
// 加上子树
for (int i = 0; i < vecData.size(); i++) {
DataConf dataConf;
dataConf = vecData[i];
QTreeWidgetItem *sonItem = new QTreeWidgetItem();
// 查typeData
this->mysqlData->GetTypeData(dataConf.carid, dataConf.sonid, typeData);
QString strTitle = "";
// 得到标题
this->mysqlData->GetTMenuTitle(typeData.carid, typeData.textid, strTitle);
sonItem->setText(0, strTitle);
if (vecData[i].visible == "0") { // 不可见的就设置其他颜色
sonItem->setForeground(0, QBrush(QColor("#0000FF")));
}
sonItem->setData(0, Qt::UserRole, QVariant::fromValue(typeData));
item->addChild(sonItem);
}
}
// 树的深度
void TreeWidget::LengthTreeItem(int& count, QTreeWidgetItem*& item)
{
while(item && item->parent())
{
item = item->parent();
count++;
}
}
// 单击事件槽函数
void TreeWidget::ShowMenuData(QTreeWidgetItem * item, int column)
{
if (item->parent() != nullptr) {
if (qApp->mouseButtons() == Qt::LeftButton) {
// 本身
TypeData typeData = item->data(0, Qt::UserRole).value<TypeData>();
// 父亲
TypeData typeFatherData = item->parent()->data(0, Qt::UserRole).value<TypeData>();
// 单击树节点发送信号
// void NotifyMenuData(TypeData& typeData, TypeData& typeFatherData);
emit(NotifyMenuData(typeData, typeFatherData));
} else if (qApp->mouseButtons() == Qt::RightButton) {
this->menu->exec(QCursor::pos());
}
}
}
// 设置配置信息
void TreeWidget::SetCarItem()
{
qDebug() << "SetCarItem";
QTreeWidgetItem *item = this->currentItem(); //获取光标所在位置的Item
TypeData typeData = item->data(0, Qt::UserRole).value<TypeData>();
Dialog dialog; // 模态对话框
dialog.mysqlData = this->mysqlData;
dialog.typeData = typeData;
dialog.SetWindowData();
int r = dialog.exec();
// 按下是确定要跟tree中的typedata
if(r == QDialog::Accepted) {
// 重新设置当前节点
typeData = dialog.typeData;
QString strTitle = "";
this->mysqlData->GetTMenuTitle(typeData.carid, typeData.textid, strTitle);
item->setText(0, strTitle);
item->setData(0, Qt::UserRole, QVariant::fromValue(typeData));
this->setCurrentItem(item);
qDebug() << "accepted";
} else if(r == QDialog::Rejected) {
qDebug() << "Rejected";
}
}
// 删除当前节点
void TreeWidget::DeleteCarItem()
{
QTreeWidgetItem *item = this->currentItem(); //获取光标所在位置的Item
this->DeleteItem(item);
}
// 设置孩子子目录
void TreeWidget::SetSonItem()
{
QTreeWidgetItem *item = this->currentItem(); //获取光标所在位置的Item
TypeData typeData = item->data(0, Qt::UserRole).value<TypeData>();
SetConfDialog formDialog; // 模态对话框
formDialog.mysqlData = this->mysqlData;
formDialog.typeData = typeData;
formDialog.InitUI();
int r = formDialog.exec(); // 显示后阻塞
// 按下是确定要跟tree中的typedata
if(r == QDialog::Accepted) {
qDebug() << "accepted";
} else if(r == QDialog::Rejected) {
qDebug() << "Rejected";
}
}
// 添加子车系
void TreeWidget::AddSonItem()
{
QTreeWidgetItem *item = this->currentItem(); //获取光标所在位置的Item
TypeData typeData = item->data(0, Qt::UserRole).value<TypeData>();
AddSonDialog addDialog; // 模态对话框
addDialog.mysqlData = this->mysqlData;
addDialog.typeData.carid = typeData.carid;
addDialog.strfathId = typeData.id;
int r = addDialog.exec(); // 显示后阻塞
// 按下是确定要跟tree中的typedata
if(r == QDialog::Accepted) {
typeData = addDialog.typeData;
QTreeWidgetItem *sonItem = new QTreeWidgetItem();
QString strTitle;
// 得到标题
this->mysqlData->GetTMenuTitle(typeData.carid, typeData.textid, strTitle);
sonItem->setText(0, strTitle);
sonItem->setData(0, Qt::UserRole, QVariant::fromValue(typeData));
// 加上子链
item->addChild(sonItem);
} else if(r == QDialog::Rejected) {
qDebug() << "Rejected AddSonItem() ";
}
}
// 拷贝
void TreeWidget::CopyItem()
{
QTreeWidgetItem *item = this->currentItem(); //获取光标所在位置的Item
this->currentTypeData = item->data(0, Qt::UserRole).value<TypeData>();
flagType = true; // 粘贴设置true,可粘贴
}
// 粘贴
void TreeWidget::PasteItem()
{
if (flagType == true) {
TypeData sonTypeData = this->currentTypeData;
QTreeWidgetItem *item = this->currentItem(); //获取光标所在位置的Item
TypeData typeData = item->data(0, Qt::UserRole).value<TypeData>();
QString fatherId = typeData.id;
sonTypeData.carid = typeData.carid;
DataProcess::InsertSql(this->mysqlData, sonTypeData, fatherId);
QTreeWidgetItem *sonItem = new QTreeWidgetItem();
QString strTitle = "";
// 得到标题
this->mysqlData->GetTMenuTitle(typeData.carid, typeData.textid, strTitle);
sonItem->setText(0, strTitle);
sonItem->setData(0, Qt::UserRole, QVariant::fromValue(sonTypeData));
// 加上子链
item->addChild(sonItem);
}
}
// 剪切
void TreeWidget::ShearItem()
{
QTreeWidgetItem *item = this->currentItem(); //获取光标所在位置的Item
this->currentTypeData = item->data(0, Qt::UserRole).value<TypeData>();
this->flagType = true;
this->DeleteItem(item);
}
// 删除一个车系
void TreeWidget::DeleteItem(QTreeWidgetItem*& item)
{
TypeData typeData = item->data(0, Qt::UserRole).value<TypeData>();
QString strSonId = typeData.id;
// 得到父节点
QTreeWidgetItem* fatherItem = item->parent();
TypeData typeFatherData = fatherItem->data(0, Qt::UserRole).value<TypeData>();
QString strFatherId = typeFatherData.id;
// 删除DataConf表中值
this->mysqlData->DeleteDataConf(typeData.carid, strFatherId, strSonId);
fatherItem->removeChild(item);
if (item != nullptr) {
delete item;
item = nullptr;
}
}
//
TreeWidget::~TreeWidget()
{
if (this->action8 != nullptr) {
delete this->action8;
this->action8 = nullptr;
}
if (this->action6 != nullptr) {
delete this->action6;
this->action6 = nullptr;
}
if (this->action5 != nullptr) {
delete this->action5;
this->action5 = nullptr;
}
if (this->action4 != nullptr) {
delete this->action4;
this->action4 = nullptr;
}
if (this->action3 != nullptr) {
delete this->action3;
this->action3 = nullptr;
}
if (this->action2 != nullptr) {
delete this->action2;
this->action2 = nullptr;
}
if (this->action1 != nullptr) {
delete this->action1;
this->action1 = nullptr;
}
if (this->menu != nullptr) {
delete this->menu;
this->menu = nullptr;
}
if (this->delphItem != nullptr) {
delete this->delphItem;
this->delphItem = nullptr;
}
}
#ifndef TREEWIDGET_H
#define TREEWIDGET_H
#include <QWidget>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QApplication>
#include <QDebug>
#include <QStyleFactory>
#include <QScrollBar>
#include <QMenu>
#include <QAction>
#include "mysqldata.h"
#include "typedata.h"
// 车系界面树状图
class TreeWidget : public QTreeWidget
{
Q_OBJECT
public:
explicit TreeWidget(QTreeWidget *parent = nullptr);
~TreeWidget();
void DeleteItem(QTreeWidgetItem*& item);
// 树的深度
void LengthTreeItem(int& count, QTreeWidgetItem*& item);
// 添加第一深度的内容
void AddOneItem(QTreeWidgetItem*& item);
// 添加第0深度的内容
void AddZeroItem(QTreeWidgetItem*& item);
public:
void InitUI(); //初始化界面
public:
QTreeWidgetItem *delphItem = nullptr;
MysqlData* mysqlData = nullptr;
QMenu* menu = nullptr;
QAction* action1 = nullptr;
QAction* action2 = nullptr;
QAction* action3 = nullptr;
QAction* action4 = nullptr;
QAction* action5 = nullptr;
QAction* action6 = nullptr;
QAction* action8 = nullptr;
TypeData currentTypeData;
bool flagType = false;
public slots:
// 双击事件的槽函数
void ShowSonItem(QTreeWidgetItem * item, int column);
// 单击事件槽函数
void ShowMenuData(QTreeWidgetItem * item, int column);
// 设置车系详细信息
void SetCarItem();
// 添加子车系
void AddSonItem();
// 删除指定车系
void DeleteCarItem();
// 设置子车系目录
void SetSonItem();
// 拷贝
void CopyItem();
// 粘贴
void PasteItem();
// 剪切
void ShearItem();
// 添加车系Item
void AddCarItem(QTreeWidgetItem*& item, TypeData& typeData);
signals:
void NotifyMenuData(TypeData typeData, TypeData typeFatherData);
};
#endif // TREEWIDGET_H
// 递归删除treeItem子节点避免内存泄漏
void DataProcess::DeleteSonItem(QTreeWidgetItem * item)
{
if (item->childCount() != 0) {
int count = item->childCount();
while (count--) {
QTreeWidgetItem * childItem = item->child(count); //index从大到小区做删除处理
DataProcess::DeleteSonItem(childItem);
item->removeChild(childItem);
if (childItem != nullptr) {
delete childItem;
childItem = nullptr;
}
}
}
}