介绍
此文章记录QTreeWidget的重写进度,暂时停滞使用,重写了QTreeWidget的拖拽功能,和绘制功能,自定义了数据结构,增加复制,粘贴,删除,准备实现动态刷新数据支持千万数据动态刷新,重写了部分代码,重写了滑块拖拽但是有bug。
效果展示
实现功能
- 实现了自定义节点类来存储数据。
- item采用Label来实现富文本显示(数据量大不建议使用)。
- 重写了QTreeWidget拖拽,滚动,绘制。
- 拖拽实现了节点与节点之间的互相拖拽,仅移动。
- 实现了节点的递归遍历,查找,插入,删除。
- 实现了滚动刷新数据,大量数据也不卡,但是滚动条刷新数据稍微复杂未完成,且有bug。
代码
#ifndef MYTREEWIDGET_H
#define MYTREEWIDGET_H
#include <QWidget>
#include <QtWidgets>
#include <QDebug>
class MyTreeWidgetItem;
class TreeNode;
class MyLabel;
// 自定义节点类
class TreeNode {
public:
QString nodeText;
QString nodeItemTest;
QList<TreeNode*> children;
TreeNode* parent = nullptr;
MyTreeWidgetItem* item;
// 重载==运算符以判断nodeText是否相等
bool operator==(const TreeNode& other) const {
return nodeText == other.nodeText;
}
};
class MyTreeWidgetItem :public QTreeWidgetItem
{
public:
MyTreeWidgetItem();
void setNodeText(QString str);
QString getNodeText();
QString m_Text;
MyLabel* m_Label;
int indexOfChild(QTreeWidgetItem *child)
{
int childCount = this->childCount();
for (int i = 0; i < childCount; ++i) {
if (this->child(i) == child) {
return i;
}
}
return -1;
}
};
class MyLabel : public QLabel
{
Q_OBJECT
public:
MyLabel(QString text, QWidget *parent = nullptr);
bool m_IsSelect = false;
bool m_IsLeave = true;
QString enterStyle;
QString leaveStyle;
QString selectStyle;
protected:
bool eventFilter(QObject *watched, QEvent *event);
};
class MyTreeWidget : public QTreeWidget
{
Q_OBJECT
public:
MyTreeWidget(QWidget *parent = nullptr);
QList<TreeNode*> m_ListData;
void wait(int ms); //等待
// 删除具有特定文本的节点及其子节点
bool deleteNodeByText(const QString& targetText) {
for (int i = 0; i < m_ListData.size(); ++i) {
TreeNode* node = m_ListData.at(i);
if (node->nodeText == targetText) {
// 找到目标节点,删除其子节点
qDeleteAll(node->children);
delete node;
m_ListData.removeAt(i);
return true; // 成功删除节点
}
}
return false; // 未找到匹配的节点
}
//删除指定父节点下的子节点
bool deleteChildNode(TreeNode* node, const QString& nodeText) {
for (int i = 0; i < node->children.size(); ++i) {
if (node->children.at(i)->nodeText == nodeText) {
node->children.removeAt(i);
return true;
}
}
return false;
}
//根据nodeText递归查找该对象
TreeNode* recursiveFindNodeByText(const QString& targetText, TreeNode* currentNode) {
if (currentNode->nodeText == targetText) {
return currentNode;
}
for (TreeNode* child : currentNode->children) {
TreeNode* result = recursiveFindNodeByText(targetText, child);
if (result) {
return result;
}
}
return nullptr; // 未找到匹配的节点
}
//根据nodeText递归查找该对象
TreeNode* findNodeByText(const QString& targetText, const QList<TreeNode*>& nodeList) {
for (TreeNode* node : nodeList) {
TreeNode* result = recursiveFindNodeByText(targetText, node);
if (result) {
return result;
}
}
return nullptr; // 未找到匹配的节点
}
//插入字节点 包括数据更新
TreeNode* insertChileItem(TreeNode* parentNode, int row, QString itemText);
//追加子节点
TreeNode* appendChileItem(TreeNode* parentNode, QString itemText);
//插入顶部节点
TreeNode* insertTopItem(int row, QString itemText, bool isInster = true);
//
void updateItem(int row, TreeNode* node);
//追加顶部节点
TreeNode* appendTopItem(QString itemText);
//删除顶部的item 以及数据列表
void removeTopItem(TreeNode* node);
//一个更新nodetext的变量保证每次更新节点都会变化
int number = 0;
double m_NodeSize = 0;
double m_ScrollBarValue = 0;
bool m_BarValueChangedTemp = false;
bool m_WheelEventTemp = false;
//递归插入
void RecursionInsert(TreeNode* ParentNode, TreeNode* childNode);
//展开所有子节点
void expandAllItems(QTreeWidget* treeWidget, QTreeWidgetItem* item);
void onScrollBarValueChanged(int value);
protected:
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void startDrag(Qt::DropActions supportedActions);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
void paintEvent(QPaintEvent* event);
void wheelEvent(QWheelEvent *event);
private:
TreeNode* m_CopyNode = nullptr; //当前拷贝的节点
QPoint m_DragMovePos; //拖拽移动坐标
QPoint m_CurPos; //点击保存坐标
int m_LastScrollBarValue = 0;
QMenu* m;
MyTreeWidgetItem* m_CurrDragItem = nullptr; //保存当前正在拖拽的对象
QScrollBar *m_VerticalScrollBar;
};
#endif // MYTREEWIDGET_H
/*******************************************************************************
* Copyright [2023] <键鼠自动化>
* All rights reserved.
*
* version: 1.0
* author: lx
* brief: 自定义item,重写绘制和拖拽,以及建立数据结构
*******************************************************************************/
#include "mytreewidget.h"
MyTreeWidget::MyTreeWidget(QWidget *parent): QTreeWidget(parent)
{
setDragEnabled(true);
setAcceptDrops(true);
setDragDropMode(DragDropMode::InternalMove);
setHeaderHidden(true);
m_VerticalScrollBar = this->verticalScrollBar();
connect(m_VerticalScrollBar, &QScrollBar::valueChanged, this, &MyTreeWidget::onScrollBarValueChanged);
m = new QMenu(this);
QAction* action1 = new QAction("删除");
QAction* action2 = new QAction("复制");
QAction* action3 = new QAction("粘贴");
connect(action1, &QAction::triggered, [=]() {
MyTreeWidgetItem* targetItem = dynamic_cast<MyTreeWidgetItem*>(itemAt(m_CurPos));
if (targetItem) {
TreeNode* targetNode = findNodeByText(targetItem->getNodeText(), m_ListData);
if (targetNode->parent == nullptr) {
this->removeTopItem(targetNode);
}
else {
targetNode->parent->item->removeChild(targetNode->item);
deleteChildNode(targetNode->parent, targetNode->nodeText);
}
}
qDebug() << "1231231";
});
connect(action2, &QAction::triggered, [=](){
MyTreeWidgetItem* targetItem = dynamic_cast<MyTreeWidgetItem*>(itemAt(m_CurPos));
if (targetItem) {
m_CopyNode = findNodeByText(targetItem->getNodeText(), m_ListData);
}
});
connect(action3, &QAction::triggered, [=]() {
MyTreeWidgetItem* targetItem = dynamic_cast<MyTreeWidgetItem*>(itemAt(m_CurPos));
if (targetItem && m_CopyNode != nullptr) {
TreeNode* targetNode = findNodeByText(targetItem->getNodeText(), m_ListData);
if (targetNode->parent == nullptr) {
int targetRow = this->indexOfTopLevelItem(targetNode->item);
if (m_CopyNode->children.isEmpty()) {
this->insertTopItem(targetRow + 1, m_CopyNode->nodeItemTest);
}
else {
TreeNode* newParentNode = this->insertTopItem(targetRow + 1, m_CopyNode->nodeItemTest);
for (int i = 0 ; i < m_CopyNode->children.size(); ++i) {
this->RecursionInsert(newParentNode, m_CopyNode->children.at(i));
}
}
}
else {
int targetRow = targetNode->parent->item->indexOfChild(targetNode->item);
if (m_CopyNode->children.isEmpty()) {
this->insertChileItem(targetNode->parent, targetRow + 1, m_CopyNode->nodeItemTest);
}
else {
TreeNode* newParentNode = this->insertChileItem(targetNode->parent, targetRow + 1, m_CopyNode->nodeItemTest);
for (int i = 0 ; i < m_CopyNode->children.size(); ++i) {
this->RecursionInsert(newParentNode, m_CopyNode->children.at(i));
}
}
}
m_CopyNode = nullptr;
}
});
m->addAction(action1);
m->addAction(action2);
m->addAction(action3);
}
void MyTreeWidget::wait(int ms)
{
QElapsedTimer t;
t.start();
while (t.elapsed() < ms)
QCoreApplication::processEvents();
}
TreeNode *MyTreeWidget::insertChileItem(TreeNode *parentNode, int row, QString itemText)
{
number++;
QTreeWidgetItem* parentItem = parentNode->item; //获取父节点
MyTreeWidgetItem* childItem = new MyTreeWidgetItem(); //创建子节点
childItem->setNodeText(QString("child%1").arg(number));
MyLabel* label = new MyLabel(itemText); //创建label
childItem->m_Label = label;
TreeNode* childData = new TreeNode; //创建子节点对象数据
childData->parent = parentNode;
childData->item = childItem;
childData->nodeText = QString("child%1").arg(number);
childData->nodeItemTest = itemText;
parentNode->children.insert(row, childData); //父节点对象数据插入子节点
parentItem->insertChild(row, childItem); //父节点item插入子节点item
setItemWidget(childItem, 0, label); //item转换lable
return childData;
}
TreeNode *MyTreeWidget::appendChileItem(TreeNode *parentNode, QString itemText)
{
number++;
QTreeWidgetItem* parentItem = parentNode->item;
MyTreeWidgetItem* childItem = new MyTreeWidgetItem();
childItem->setNodeText(QString("child%1").arg(number));
MyLabel* label = new MyLabel(itemText);
childItem->m_Label = label;
TreeNode* childData = new TreeNode;
childData->parent = parentNode;
childData->item = childItem;
childData->nodeText = QString("child%1").arg(number);
childData->nodeItemTest = itemText;
parentNode->children.append(childData);
parentItem->addChild(childItem);
setItemWidget(childItem, 0, label);
return childData;
}
TreeNode* MyTreeWidget::insertTopItem(int row, QString itemText, bool isInster)
{
number++;
MyTreeWidgetItem* parentItem = new MyTreeWidgetItem();
parentItem->setNodeText(QString("parent%1").arg(number));
TreeNode* parentData = new TreeNode;
parentData->item = parentItem;
parentData->nodeText = QString("parent%1").arg(number);
parentData->nodeItemTest = itemText;
if (isInster) {
MyLabel* label = new MyLabel(itemText);
parentItem->m_Label = label;
insertTopLevelItem(row, parentItem);
setItemWidget(parentItem, 0, label);
}
m_ListData.insert(row, parentData);
return parentData;
}
void MyTreeWidget::updateItem(int row, TreeNode *node)
{
qDebug() << row << node->nodeItemTest << "aaaa";
MyLabel* label = new MyLabel(node->nodeItemTest);
node->item->m_Label = label;
insertTopLevelItem(row, node->item);
// setItemWidget(node->item, 0, label);
}
TreeNode *MyTreeWidget::appendTopItem(QString itemText)
{
number++;
MyTreeWidgetItem* parentItem = new MyTreeWidgetItem();
parentItem->setNodeText(QString("parent%1").arg(number));
MyLabel* label = new MyLabel(itemText);
parentItem->m_Label = label;
TreeNode* parentData = new TreeNode;
parentData->item = parentItem;
parentData->nodeText = QString("parent%1").arg(number);
parentData->nodeItemTest = itemText;
addTopLevelItem(parentItem);
setItemWidget(parentItem, 0, label);
m_ListData.append(parentData);
return parentData;
}
void MyTreeWidget::removeTopItem(TreeNode *node)
{
int index = indexOfTopLevelItem(node->item);
takeTopLevelItem(index);
deleteNodeByText(node->nodeText);
}
void MyTreeWidget::RecursionInsert(TreeNode *ParentNode, TreeNode *childNode)
{
TreeNode* node = this->appendChileItem(ParentNode, childNode->nodeItemTest);
for (int i = 0 ; i < childNode->children.size(); ++i) {
this->RecursionInsert(node, childNode->children.at(i));
}
}
void MyTreeWidget::expandAllItems(QTreeWidget *treeWidget, QTreeWidgetItem *item)
{
if (item) {
treeWidget->expandItem(item); // 展开当前项
// 递归展开子项
for (int i = 0; i < item->childCount(); ++i) {
expandAllItems(treeWidget, item->child(i));
}
}
}
void MyTreeWidget::onScrollBarValueChanged(int value)
{
//m_BarValueChangedTemp用于该函数在没有结束的时候又进来了如果不调用takeTopLevelItem就没事,如果没有m_BarValueChangedTemp在该函数未结束还会进入导致崩溃
int step = 3; //滚动一次刷新三条数据
if (value >= m_VerticalScrollBar->maximum()) {
for (int index = 0; index < 1; ++index) {
int itemCount = this->topLevelItemCount();
MyTreeWidgetItem* bottomItem = dynamic_cast<MyTreeWidgetItem*>(this->topLevelItem(itemCount - 1));
TreeNode* bottomNode = findNodeByText(bottomItem->getNodeText(), m_ListData);
int bottomIndex = m_ListData.indexOf(bottomNode);
if (bottomIndex + 100 < m_ListData.size()) {
step = 1000;
}
else {
step = (m_ListData.size() - 1) - bottomIndex;
}
for (int i = 0 ; i < step; ++i) {
//尾部追加显示
//获取当前底部的数据
bottomIndex++;
updateItem(itemCount, m_ListData.at(bottomIndex));
itemCount++;
}
for (int i = 0 ; i < step; ++i) {
takeTopLevelItem(0);
}
}
qDebug() << QDateTime::currentDateTime() << "222222222222222222";
m_VerticalScrollBar->setValue(value-5);
}
/* if (m_BarValueChangedTemp) {
qDebug() << "onScrollBarValueChanged未结束就进入";
return;
}
if (m_WheelEventTemp) {
qDebug() << "wheelEvent正在滚动中";
return;
}
m_BarValueChangedTemp = true;
qDebug() << value << m_LastScrollBarValue<< this->topLevelItemCount();
int step = 3; //滚动一次刷新三条数据
if (m_LastScrollBarValue > value) {
// 上拉
int number = m_LastScrollBarValue - value;
for (int index = 0; index < number; ++index) {
MyTreeWidgetItem* topItem = dynamic_cast<MyTreeWidgetItem*>(this->topLevelItem(0));
TreeNode* topNode = findNodeByText(topItem->getNodeText(), m_ListData);
int topIndex = m_ListData.indexOf(topNode);
if (topIndex - 3 > 0) {
step = 3;
}
else {
step = topIndex;
}
for (int i = step; i > 0; --i) {
//尾部追加显示
//获取当前底部的数据
topIndex--;
updateItem(0, m_ListData.at(topIndex));
}
for (int i = 0 ; i < step; ++i) {
takeTopLevelItem(this->topLevelItemCount() - 1);
}
}
}
else {
int number = value - m_LastScrollBarValue;
qDebug() << QDateTime::currentDateTime() << "111111111111111";
for (int index = 0; index < number; ++index) {
int itemCount = this->topLevelItemCount();
MyTreeWidgetItem* bottomItem = dynamic_cast<MyTreeWidgetItem*>(this->topLevelItem(itemCount - 1));
TreeNode* bottomNode = findNodeByText(bottomItem->getNodeText(), m_ListData);
int bottomIndex = m_ListData.indexOf(bottomNode);
if (bottomIndex + 3 < m_ListData.size()) {
step = 3;
}
else {
step = (m_ListData.size() - 1) - bottomIndex;
}
for (int i = 0 ; i < step; ++i) {
//尾部追加显示
//获取当前底部的数据
bottomIndex++;
updateItem(itemCount, m_ListData.at(bottomIndex));
itemCount++;
}
for (int i = 0 ; i < step; ++i) {
takeTopLevelItem(0);
}
}
qDebug() << QDateTime::currentDateTime() << "222222222222222222";
}
m_ScrollBarValue = value;
m_LastScrollBarValue = value;
m_VerticalScrollBar->setValue(value);
m_BarValueChangedTemp = false;*/
}
void MyTreeWidget::mouseMoveEvent(QMouseEvent *event)
{
QTreeWidget::mouseMoveEvent(event);
}
void MyTreeWidget::mousePressEvent(QMouseEvent *event)
{
QTreeWidget::mousePressEvent(event);
m_CurPos = event->pos();
if (event->buttons() & Qt::RightButton) {
m->move((QCursor::pos()));
m->show();
}
}
void MyTreeWidget::mouseReleaseEvent(QMouseEvent *event)
{
QTreeWidget::mouseReleaseEvent(event);
}
void MyTreeWidget::startDrag(Qt::DropActions supportedActions)
{
//拖拽重写此函数下发当前拖拽对象的nodetext
Q_UNUSED(supportedActions);
MyTreeWidgetItem* currItem = dynamic_cast<MyTreeWidgetItem*>(this->currentItem());
if (currItem) {
QString text = currItem->getNodeText();
QMimeData* mimeData = new QMimeData;
mimeData->setData("application/labelData", text.toUtf8());
QDrag* drag = new QDrag(this);
drag->setMimeData(mimeData);
m_CurrDragItem = currItem;
drag->start(Qt::MoveAction);
}
}
void MyTreeWidget::dragEnterEvent(QDragEnterEvent *event)
{
QTreeWidget::dragEnterEvent(event);
// 检查拖拽数据格式
if (event->mimeData()->hasFormat("application/labelData")) {
event->acceptProposedAction();
}
}
void MyTreeWidget::dragMoveEvent(QDragMoveEvent *event)
{
QTreeWidget::dragMoveEvent(event);
// 检查拖拽数据格式
if (event->mimeData()->hasFormat("application/labelData")) {
event->acceptProposedAction();
m_DragMovePos = event->pos();
viewport()->update();
}
}
void debugTreeData(TreeNode* node, int depth = 0) {
QString kongge;
for (int i = 0; i < depth; ++i) {
kongge.append("----");
}
qDebug() << kongge << node->nodeItemTest << node->nodeText;
for (int i = 0; i < node->children.size(); ++i) {
debugTreeData(node->children.at(i), depth + 1); // 递归时深度加1
}
}
void MyTreeWidget::dropEvent(QDropEvent *event)
{
// 检查拖拽数据格式
if (event->mimeData()->hasFormat("application/labelData")) {
QString itemData = event->mimeData()->data("application/labelData");
MyTreeWidgetItem* targetItem = dynamic_cast<MyTreeWidgetItem*>(itemAt(event->pos()));
m_CurrDragItem = nullptr;
if (!targetItem) {
return;
}
qDebug() << itemData << "-------------------" << targetItem->getNodeText();
TreeNode* targetNode = findNodeByText(targetItem->getNodeText(), m_ListData);
TreeNode* sourceNode = findNodeByText(itemData, m_ListData);
if (sourceNode && targetNode) {
// 找到了匹配的节点,可以对其进行操作
qDebug() << "找到了匹配的节点,可以对其进行操作" << targetNode->nodeText << sourceNode->nodeText;
if (sourceNode->parent == nullptr && targetNode->parent == nullptr) { //父与父
//当前是父节点与父节点直接拖拽
int targetRow = this->indexOfTopLevelItem(targetNode->item);
int sourceRow = this->indexOfTopLevelItem(sourceNode->item);
if (targetRow != sourceRow) {
qDebug() << "1111111111111111" << targetRow << sourceRow;
//在目标源下插入一行
if (sourceNode->children.isEmpty()) {
this->insertTopItem(targetRow + 1, sourceNode->nodeItemTest);
//删除来源item
this->removeTopItem(sourceNode);
}
else if (!sourceNode->children.isEmpty()) {
//如果来源里面有子节点就需要递归插入,先查入头节点
TreeNode* newParentNode = this->insertTopItem(targetRow + 1, sourceNode->nodeItemTest);
for (int i = 0 ; i < sourceNode->children.size(); ++i) {
this->RecursionInsert(newParentNode, sourceNode->children.at(i));
}
//删除来源item
this->removeTopItem(sourceNode);
deleteNodeByText(sourceNode->nodeText);
}
else {
qDebug() << "未知动作!!!!!!!!!!!!!!!!!!!!!!!!";
}
}
}
else if (sourceNode->parent != nullptr && targetNode->parent != nullptr) { //子与子
//双方都是子节点
int targetRow = targetNode->parent->item->indexOfChild(targetNode->item);
int sourceRow = sourceNode->parent->item->indexOfChild(sourceNode->item);
qDebug() << "44444444444444" << targetRow << sourceRow << sourceNode->nodeItemTest << targetNode->nodeItemTest;
if (recursiveFindNodeByText(targetNode->nodeText, sourceNode) != nullptr) {
//来源节点中不能有目标节点
return;
}
if (sourceNode->children.isEmpty()) {
this->insertChileItem(targetNode->parent, targetRow + 1, sourceNode->nodeItemTest);
sourceNode->parent->item->removeChild(sourceNode->item);
deleteChildNode(sourceNode->parent, sourceNode->nodeText);
}
else if (!sourceNode->children.isEmpty()) {
TreeNode* newParentNode = this->insertChileItem(targetNode->parent, targetRow + 1, sourceNode->nodeItemTest);
for (int i = 0 ; i < sourceNode->children.size(); ++i) {
this->RecursionInsert(newParentNode, sourceNode->children.at(i));
}
//删除来源item
sourceNode->parent->item->removeChild(sourceNode->item);
deleteChildNode(sourceNode->parent, sourceNode->nodeText);
}
}
else if (sourceNode->parent != nullptr && targetNode->parent == nullptr) { //子与父
//来源是子节点,指向端是父节点
int targetRow = this->indexOfTopLevelItem(targetNode->item);
int sourceRow = sourceNode->parent->item->indexOfChild(sourceNode->item);
qDebug() << "222222222222222222" << targetRow << sourceRow << sourceNode->parent->nodeItemTest << sourceNode->nodeItemTest;
if (sourceNode->children.isEmpty()) {
this->insertTopItem(targetRow + 1, sourceNode->nodeItemTest);
sourceNode->parent->item->removeChild(sourceNode->item);
deleteChildNode(sourceNode->parent, sourceNode->nodeText);
}
else if (!sourceNode->children.isEmpty()) {
TreeNode* newParentNode = this->insertTopItem(targetRow + 1, sourceNode->nodeItemTest);
for (int i = 0 ; i < sourceNode->children.size(); ++i) {
this->RecursionInsert(newParentNode, sourceNode->children.at(i));
}
//删除来源item
sourceNode->parent->item->removeChild(sourceNode->item);
deleteChildNode(sourceNode->parent, sourceNode->nodeText);
}
}
else if (sourceNode->parent == nullptr && sourceNode->children.isEmpty() && targetNode->parent != nullptr) { //空父 与子
//来源父节点 且没有子节点 且指向端是子节点
int targetRow = targetNode->parent->item->indexOfChild(targetNode->item);
int sourceRow = this->indexOfTopLevelItem(sourceNode->item);
qDebug() << "333333333333" << targetRow << sourceRow << sourceNode->nodeItemTest << targetNode->nodeItemTest;
this->insertChileItem(targetNode->parent, targetRow + 1, sourceNode->nodeItemTest);
this->removeTopItem(sourceNode);
}
else if (sourceNode->parent == nullptr && !sourceNode->children.isEmpty() && targetNode->parent != nullptr) { //父多子 与子
//来源父节点 有子节点 且指向端是子节点
if (recursiveFindNodeByText(targetNode->nodeText, sourceNode) != nullptr) {
//来源节点中不能有目标节点
return;
}
int targetRow = targetNode->parent->item->indexOfChild(targetNode->item);
int sourceRow = this->indexOfTopLevelItem(sourceNode->item);
qDebug() << "5555555555555" << targetRow << sourceRow << sourceNode->nodeItemTest << targetNode->nodeItemTest;
TreeNode* newParentNode = this->insertChileItem(targetNode->parent, targetRow + 1, sourceNode->nodeItemTest);
for (int i = 0 ; i < sourceNode->children.size(); ++i) {
this->RecursionInsert(newParentNode, sourceNode->children.at(i));
}
//删除来源item
this->removeTopItem(sourceNode);
deleteNodeByText(sourceNode->nodeText);
}
} else {
// 未找到匹配的节点
qDebug() << "未找到匹配的节点2";
}
}
// for (int i = 0; i < m_ListData.size(); ++i) {
// debugTreeData(m_ListData.at(i));
// }
}
void MyTreeWidget::paintEvent(QPaintEvent *event)
{
// qDebug() << "123123123123";
QTreeWidget::paintEvent(event);
QPainter painter(viewport());
if (m_CurrDragItem != nullptr) {
QModelIndex hoveredIndex = indexAt(m_DragMovePos);
MyTreeWidgetItem* mcurrMoveItem = dynamic_cast<MyTreeWidgetItem*>(itemFromIndex(hoveredIndex));
if (mcurrMoveItem) {
QRect rect = visualRect(hoveredIndex); // 获取悬停项的矩形区域
QString labelText = mcurrMoveItem->m_Label->text();
qDebug()<< "---------------" << labelText << rect << "-----------------";
painter.setPen(QPen(QColor(34, 142, 243), 2)); // 设置线条颜色和粗细
// 绘制线条
painter.drawLine(rect.x() + 6, rect.y() + rect.height(), rect.x() + rect.width() - 6, rect.y() + rect.height()); // 绘制底部线条
// 绘制头部小圆圈
painter.setBrush(QBrush(QColor(34, 142, 243))); // 设置圆圈颜色
painter.drawEllipse(QPoint(rect.x() + 2, rect.y() + rect.height()), 2, 2); // 绘制小圆圈
// 绘制尾部小圆圈
painter.drawEllipse(QPoint(rect.x() + rect.width()-2, rect.y() + rect.height()), 2, 2); // 绘制小圆圈
}
}
}
void MyTreeWidget::wheelEvent(QWheelEvent *event)
{
if (m_WheelEventTemp) {
qDebug() << "wheelEvent未结束就进入";
return;
}
if (m_VerticalScrollBar->isSliderDown()) {
qDebug() << "正在拖拽滚动条";
return;
}
m_WheelEventTemp = true;
qDebug() << "1111111111111111111" << event->angleDelta().y() <<this->topLevelItemCount() << m_VerticalScrollBar->isSliderDown();
int number = qAbs(event->angleDelta().y()) / 120;
int step = 3; //滚动一次刷新三条数据
for (int i = 0; i < number; ++i) {
if (event->angleDelta().y() > 0) {
MyTreeWidgetItem* topItem = dynamic_cast<MyTreeWidgetItem*>(this->topLevelItem(0));
TreeNode* topNode = findNodeByText(topItem->getNodeText(), m_ListData);
int topIndex = m_ListData.indexOf(topNode);
if (topIndex - 3 > 0) {
step = 3;
}
else {
step = topIndex;
}
for (int i = step; i > 0; --i) {
//尾部追加显示
//获取当前底部的数据
topIndex--;
updateItem(0, m_ListData.at(topIndex));
}
for (int i = 0 ; i < step; ++i) {
takeTopLevelItem(this->topLevelItemCount() - 1);
}
if (m_ScrollBarValue > 0) {
m_ScrollBarValue -= double(m_VerticalScrollBar->maximum()) / double(m_ListData.size() / (step == 0 ? 1 : step));
qDebug() << "向上滚动" << topIndex <<m_ScrollBarValue;
m_VerticalScrollBar->setValue(m_ScrollBarValue);
}
}
else {
int itemCount = this->topLevelItemCount();
MyTreeWidgetItem* bottomItem = dynamic_cast<MyTreeWidgetItem*>(this->topLevelItem(itemCount - 1));
TreeNode* bottomNode = findNodeByText(bottomItem->getNodeText(), m_ListData);
int bottomIndex = m_ListData.indexOf(bottomNode);
if (bottomIndex+3 < m_ListData.size()) {
step = 3;
}
else {
step = (m_ListData.size() - 1) - bottomIndex;
}
for (int i = 0 ; i < step; ++i) {
//尾部追加显示
//获取当前底部的数据
bottomIndex++;
updateItem(itemCount, m_ListData.at(bottomIndex));
itemCount++;
}
for (int i = 0 ; i < step; ++i) {
takeTopLevelItem(0);
}
if (m_VerticalScrollBar->value() < m_VerticalScrollBar->maximum()) {
m_ScrollBarValue += double(m_VerticalScrollBar->maximum()) / double(m_ListData.size() / (step == 0 ? 1 : step));
qDebug() << "向下滚动" << bottomIndex <<m_ScrollBarValue;
m_VerticalScrollBar->setValue(m_ScrollBarValue);
}
}
}
m_WheelEventTemp = false;
}
MyTreeWidgetItem::MyTreeWidgetItem()
{
}
void MyTreeWidgetItem::setNodeText(QString str)
{
m_Text = str;
}
QString MyTreeWidgetItem::getNodeText()
{
return m_Text;
}
MyLabel::MyLabel(QString text, QWidget *parent)
: QLabel(parent)
{
setText(text);
installEventFilter(this);
enterStyle = "background-color: rgb(225, 243, 255);";
leaveStyle = "background-color: white;";
selectStyle = "background-color: rgb(204, 232, 255);";
}
bool MyLabel::eventFilter(QObject *watched, QEvent *event)
{
return QWidget::eventFilter(watched, event);
}
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
m_MyTreeWidget = new MyTreeWidget();
// if (1) {
qDebug() << QDateTime::currentDateTime() << "111111111111111";
for (int i = 0; i < 100000; ++i) {
if (i >= 100) {
m_MyTreeWidget->insertTopItem(i, QString("父节点%1").arg(i+1), false);
}
else {
m_MyTreeWidget->insertTopItem(i, QString("父节点%1").arg(i+1));
}
}
qDebug() << QDateTime::currentDateTime() << "2222222222222";
// for (int i = 0; i < 500; ++i) {
// m_MyTreeWidget->insertChileItem(m_MyTreeWidget->m_ListData.at(0), m_MyTreeWidget->m_ListData.at(0)->item->childCount(),QString("子节点%1").arg(i+1));
// }
// for (int i = 0; i < 500; ++i) {
// m_MyTreeWidget->insertChileItem(m_MyTreeWidget->m_ListData.at(1), m_MyTreeWidget->m_ListData.at(1)->item->childCount(),QString("子节点%1").arg(i+1));
// }
// for (int i = 0; i < 500; ++i) {
// m_MyTreeWidget->insertChileItem(m_MyTreeWidget->m_ListData.at(2), m_MyTreeWidget->m_ListData.at(2)->item->childCount(),QString("子节点%1").arg(i+1));
// }
// for (int i = 0; i < 500; ++i) {
// m_MyTreeWidget->insertChileItem(m_MyTreeWidget->m_ListData.at(3), m_MyTreeWidget->m_ListData.at(3)->item->childCount(),QString("子节点%1").arg(i+1));
// }
ui->gridLayout->addWidget(m_MyTreeWidget);
// 在您的代码中调用此函数来展开所有项
//m_MyTreeWidget->expandAllItems(m_MyTreeWidget, m_MyTreeWidget->invisibleRootItem());
}
Widget::~Widget()
{
delete ui;
}