QTreeView的拖拽功能

QTreeView的拖拽功能

  • Qt树形结构的拖拽功能(drag/drop)
    • 树形Model的定义
    • 树形Model的实现
    • 界面设置
    • 拖放界面的头文件
    • 拖放界面的实现
    • 源代码连接

Qt树形结构的拖拽功能(drag/drop)

QTreeView的拖拽功能_第1张图片

树形Model的定义

class TreeNode
{
public:
	TreeNode(const QString& text = "") :mText(text) {}
	~TreeNode(){}

	QString mText;

	TreeNode* mParentNode;				//父结点
	QList mChildNodes;			//孩子结点
};



class TreeModel : public QAbstractItemModel
{
public:

TreeModel(QObject* parent = NULL);
~TreeModel();

void SetRootNode(TreeNode *node);
bool AddTreeNode(TreeNode* pNode);																			//添加一个子节点
int TreeNodeHaveEqualInfo(TreeNode* parentNode, TreeNode* pAddChildNode);								//判断待加入节点,在父节点中是否有相同信息
TreeNode* FindParentNode(TreeNode* pNode, TreeNode* childNode);									//根据给定的字节点,再根节点中,寻找其父节点

//结点所在的位置,和其父结点
TreeNode* NodeFromIndex(const QModelIndex &index) const;

//实现 QAbstractItemModel的类的成员函数
QModelIndex index(int row, int column,
	const QModelIndex &parent) const;
QModelIndex parent(const QModelIndex &child) const;

int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;


//
Qt::ItemFlags flags(const QModelIndex &index) const
{
	Qt::ItemFlags flag = QAbstractItemModel::flags(index);
	return flag | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;				//允许Model拖动,这个很重要
}

QMimeData*  mimeData(const QModelIndexList &indexes) const
{
	QMimeData* mimeD = QAbstractItemModel::mimeData(indexes);				//先获取原始的mimeData;


	if (indexes.size() > 0)
	{
		QModelIndex index = indexes.at(0);

		TreeModel* node = (TreeModel*)index.internalPointer();			
		QByteArray encoded;
		QDataStream stream(&encoded, QIODevice::WriteOnly);
		stream << (qint64)(node);
		mimeD->setData("Node/NodePtr", encoded);							//将自己需要的数据 存入到MimeData中
	}
	else
		mimeD->setData("Node/NodePtr", "NULL");

	return mimeD;
	//mimeD->setData()
}

public:
TreeNode* mRootNode;							//树的根结点
};

树形Model的实现

TreeModel::TreeModel(QObject* parent) : QAbstractItemModel(parent)
{
this->mRootNode = NULL;
//构造一个根节点,在Qt中根节点的父节点为空,默认不显示,构造一个空节点充当父节点

mRootNode = new TreeNode();
mRootNode->mParentNode = NULL;
}

TreeModel::~TreeModel()
{
	//将设备的根结点才此位置析构
	if (mRootNode)
		delete mRootNode;
	mRootNode = NULL;
}

//设置设备树的根结点
void TreeModel::SetRootNode(TreeNode *node)
{
	//要更新model数据时,先调用beginResetModel,结束时调用endResetModel,所有绑定在Model上的视图都会更新
	this->beginResetModel();
	if (mRootNode)
	{
		delete mRootNode;
		mRootNode = NULL;
	}
	mRootNode = node;
	endResetModel();
}

//往某个父节点,添加一个子节点,如果parentNode为空,添加到父节点下
bool TreeModel::AddTreeNode(TreeNode* pNode)
{
	if (this->TreeNodeHaveEqualInfo(mRootNode, pNode) > 0)			//如果待加入节点,在根节点中有相同Ip,不允许加入
	{
		//TODO MSG
		delete pNode;												//不加入的节点 析构掉。
		return true;
	}
	this->beginResetModel();
	do
	{
		if (!pNode->mParentNode)						//parentNode为空,直接加载在根节点下
		{
			mRootNode->mChildNodes.append(pNode);
			pNode->mParentNode = mRootNode;
			break;
		}
	} while (0);

	//如果parentNode在现有的树体系中,加入现有树体系,如果不在,加入根节点中
	/*TreeNode* pNode = FindParentNode(mRootNode, pNode->mParentNode);
	if (!pNode)
	{
		mRootNode->mChildNodes.append(pNode);
		pNode->mParentNode = mRootNode;
		return true;
	}*/

	this->endResetModel();
	return true;
}

//pNode 为要查找节点, childNode 为被查找节点,返回被查找节点的父节点,pNode和childNode之间有层级关系
TreeNode* TreeModel::FindParentNode(TreeNode* pNode, TreeNode* childNode)
{
	//if (!pNode)
	//	return NULL;

	//if (pNode->mChildNodes.indexOf(childNode))								//如果子节点在所在的父节点,返回父节点
	//	return pNode;
	//for (int i = 0; i < pNode->mChildNodes.count(); i++)
	//{
	//	return FindParentNode(pNode->mChildNodes.at(i), childNode);
	//}
	return NULL;
}

int TreeModel::TreeNodeHaveEqualInfo(TreeNode* parentNode, TreeNode* pAddChildNode)
{
	/*for (int i = 0; i < parentNode->mChildNodes.size(); i++)
	{
		if (parentNode->mChildNodes.at(i)->mDeviceInfo.mDevIp != pAddChildNode->mDeviceInfo.mDevIp)
			continue;
		else
			return 1;
	}
	*/
	return 0;
}

//根据QModelIndex,返回指向其父结点的指针
TreeNode* TreeModel::NodeFromIndex(const QModelIndex &index) const
{
	if (index.isValid())				//如果是有效结点
		return static_cast(index.internalPointer());
	else
		return mRootNode;
}

//重载实现的QAbstractItemModel类的函数,基类中带const的函数,重载时也要是const
//index函数,根据行,列,返回一个父结点为parent的元素
QModelIndex TreeModel::index(int row, int column,
	const QModelIndex &parent) const
{
	//如果参数条件不满足,返回为空
	if (!mRootNode || row < 0 || column < 0)
		return QModelIndex();

	TreeNode* parentNode = NodeFromIndex(parent);		//获取指向此结点的指针
	if (!parentNode)					//如果没有父结点
		return QModelIndex();

	TreeNode* rowNode = parentNode->mChildNodes.at(row);
	if (!rowNode)
		return QModelIndex();
	return this->createIndex(row, column, rowNode);			//创建一个QModelIndex,参数3为结点指向数据指针
}

QModelIndex TreeModel::parent(const QModelIndex &child) const
{
	TreeNode *node = NodeFromIndex(child);
	if (!node)
		return QModelIndex();
	TreeNode *parentNode = node->mParentNode;
	if (!parentNode)
		return QModelIndex();
	TreeNode *grandparentNode = parentNode->mParentNode;
	if (!grandparentNode)
		return QModelIndex();

	int row = grandparentNode->mChildNodes.indexOf(parentNode);
	return createIndex(row, 0, parentNode);
}

//返回给定父结点下,行的个数
int TreeModel::rowCount(const QModelIndex &parent) const
{
	if (parent.column() > 0)
		return 0;
	TreeNode* parentNode = NodeFromIndex(parent);
	if (!parentNode)
		return 0;
	return parentNode->mChildNodes.count();				//返回父结点中子结点个数   
}

int TreeModel::columnCount(const QModelIndex &parent) const
{
	return 1;											//返回列数,此处为1列
}

QVariant TreeModel::data(const QModelIndex &index, int role) const
{

	qDebug() << "TreeModel::data";
	switch (role)
	{
	case Qt::DisplayRole:										//显示汉字
	{
		TreeNode *node = NodeFromIndex(index);
		if (!node)
			return QVariant();
		if (index.column() == 0)
			return node->mText;				//显示设备的Ip
	}
	break;
	case Qt::DecorationRole:									//图标相关的role
	{
		//qDebug() << "Qt::DecorationRole";
		QPixmap Icon = QPixmap("D:/QtProject/QtGuiApplication1/release/33.png");		//在树上画图标
		QVariant var;
		var.setValue(Icon);
		return var;
	}
	break;
	/*case Qt::UserRole:
	{
		TreeNode *node = NodeFromIndex(index);

		QVariant var;
		var.setValue(node);
		return var;
	}
	break;*/
	default:
		break;
	}


	return QVariant();
}

QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
	{
		if (section == 0)
		{
			return tr("Txt");
		}

	}
	return QVariant();
}

界面设置

QTreeView的拖拽功能_第2张图片

拖放界面的头文件

class TreeDrag : public QMainWindow
{
	Q_OBJECT

public:
	TreeDrag(QWidget *parent = Q_NULLPTR);

protected:
	void dropEvent(QDropEvent *event);								//放下动作
	void dragEnterEvent(QDragEnterEvent *event);					//托到进入窗口动作
	void dragMoveEvent(QDragMoveEvent *event);						//拖着物体在窗口移动
	void dragLeaveEvent(QDragLeaveEvent *event);					//拖走了没有释放
private:
	Ui::TreeDragClass ui;

	TreeModel* mModel;
};

拖放界面的实现

TreeDrag::TreeDrag(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	this->setAcceptDrops(true);				//允许接受拖拽事件
	mModel = new TreeModel(this);

	TreeNode* node = new TreeNode();
	node->mText = "Test";
	node->mParentNode = NULL;


	for (int i = 0; i < 10; i++)
	{
		TreeNode* childNode = new TreeNode();
		childNode->mText = QString("192.168.1.%1").arg(QString::number(100 + i + 1));
		childNode->mParentNode = node;
		node->mChildNodes.append(childNode);
	}

	mModel->AddTreeNode(node);

	ui.treeView->setModel(mModel);
}


void TreeDrag::dragEnterEvent(QDragEnterEvent *event)
{
	QStringList formats = event->mimeData()->formats();
	qDebug() << "dragEnterEvent formats = " << formats;
	if (event->mimeData()->hasFormat("Node/NodePtr"))
		event->accept();
	else
		event->ignore();
}

void TreeDrag::dragLeaveEvent(QDragLeaveEvent *event)
{
	qDebug() << "dragLeaveEvent";
}


void TreeDrag::dragMoveEvent(QDragMoveEvent *event)
{
	QStringList formats = event->mimeData()->formats();
	qDebug() << "dragMoveEvent formats = " << formats;
	if (event->mimeData()->hasFormat("Node/NodePtr")) {
		event->setDropAction(Qt::MoveAction);
		event->accept();
	}
	else {
		event->ignore();
	}
}

void TreeDrag::dropEvent(QDropEvent *event)
{
	QStringList formats = event->mimeData()->formats();
	qDebug() << "dropEvent formats = " << formats;
	if (event->mimeData()->hasFormat("Node/NodePtr"))
	{
		QVariant varData = event->mimeData()->data("Node/NodePtr");
		QByteArray byteData = varData.toByteArray();
		QDataStream stream(&byteData, QIODevice::ReadWrite);
		qint64 node;
		stream >> (node);
		TreeNode* devNode = (TreeNode*)(node);

		if (devNode)
			ui.lineEdit->setText(devNode->mText);

		event->setDropAction(Qt::MoveAction);
		event->accept();
	}
	else
	{
		event->ignore();
	}
}

源代码连接

源代码连接:https://download.csdn.net/download/u013125105/11653837

你可能感兴趣的:(Qt)