Examples of adding, deleting, checking, importing and dragging QTreeWidget

Origin

Because the operations of QTreeWidget in work are basically these operations. Then I never made a memo. I wrote a lot of repetitive code. Today I hereby make a reminder. For subsequent use

Function description

This TreeWidget is operated by the right-click menu. Currently supports adding, deleting, and checking QTreeWidgetItem. At the same time, you can drag and drop QTreeWidgetItem to form a new hierarchical relationship. At the same time, it supports importing from another TreeWidget to this TreeWidget. And maintain the same import hierarchical relationship.

Add implementation ideas

The QTreeWIdgetItem selected by the right button is used as the parent node. Add new child nodes directly.
Implementation code

void FCustomTreeWidget::onAddItem()
{
    
    
	auto selectItemList = this->selectedItems();
	QTreeWidgetItem *item = new QTreeWidgetItem;//构造函数给this的话 就直接添加为了顶层节点
	item->setText(0, QStringLiteral("新建节点"));
	item->setCheckState(0, Qt::CheckState::Unchecked);
	item->setFlags(item->flags() | Qt::ItemFlag::ItemIsEditable);
	if (selectItemList.size() == 0)
	{
    
    
		this->addTopLevelItem(item);
	}
	else
	{
    
    
		auto selectItem = selectItemList.first();
		selectItem->addChild(item);
	}
}

Delete the realization idea

The QTreeWIdgetItem selected by the right button is used as the parent node. Then you can choose whether to delete its child nodes.
Implementation code

void FCustomTreeWidget::onRemoveItem()
{
    
    
	auto selectItemList = this->selectedItems();
	if (selectItemList.size() == 0)
	{
    
    
		qDebug() << "Select Items Is Empty";
		return;
	}
	auto selectItem = selectItemList.first();
	QMessageBox msgBox;
	msgBox.setText(QStringLiteral("是否删除此节点的子节点"));
	msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
	msgBox.setDefaultButton(QMessageBox::Yes);
	int ret = msgBox.exec();
	if (ret == QMessageBox::Yes)
	{
    
    
		removeItemWithChild(selectItem);//递归删除子节点
	}
	else
	{
    
    
		removeItemNotWithChild(selectItem);//递归删除子节点
	}
}

Node can be edited

The implementation code can be achieved directly by setting itemFlags

QTreeWidgetItem *item = new QTreeWidgetItem;
	item->setText(0, QStringLiteral("新建节点"));
	item->setFlags(item->flags() | Qt::ItemFlag::ItemIsEditable);

Right-click pop-up menu

This implementation directly calls setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);and then implements a slot function. customContextMenuRequestedJust bind the signal. But there is one thing to note. The pop-up position of the menu is used to QCursor::pos()directly obtain the position of the mouse cursor. In this way, there will be no problems with single screen or multiple screens.
Implementation code

void FCustomTreeWidget::onCustomContextMenuRequested(const QPoint &pos)
{
    
    
	QMenu  menu(this);
	menu.addAction(_actionAddItem);
	menu.addAction(_actionAddItem);
	menu.addAction(_actionRemoveItem);
	menu.addAction(_actionSelectAll);
	menu.addAction(_actionUnselectAll);
	menu.addAction(_actionImport);
	menu.exec(QCursor::pos());
}

Checking and unchecking nodes

This operation first sets the QTreeWidgetItem to be checked. Then you can check your own node and its child nodes.
Implementation code

void FCustomTreeWidget::setItemWithChildItemCheckState(QTreeWidgetItem* item, bool isChecked)
{
    
    
	if (item == nullptr)
	{
    
    
		return;
	}
	if (isChecked)
	{
    
    
		item->setCheckState(0, Qt::CheckState::Checked);
	}
	else
	{
    
    
		item->setCheckState(0, Qt::CheckState::Unchecked);
	}
	int childCount = item->childCount();
	for (auto iter = 0;iter<childCount;++iter)
	{
    
    
		auto childItem = item->child(iter);
		setItemWithChildItemCheckState(childItem, isChecked);
	}
}

Drag and drop of nodes to change the parent-child relationship

First set the QTreeWidget can be dragged. Then rewrite the dropEventprocessing node to drop the event.
Implementation code

void FCustomTreeWidget::dropEvent(QDropEvent *event)
{
    
    
	auto selItemList = this->selectedItems();
	if (selItemList.size() <1)
	{
    
    
		return;
	}
	auto curItem = selItemList.first();
	if (curItem == nullptr)
	{
    
    
		return;
	}
	auto parentItem = curItem->parent();
	if (parentItem  == nullptr)
	{
    
    
		this->takeTopLevelItem(this->indexOfTopLevelItem(curItem));

	}
	else
	{
    
    
		parentItem->removeChild(curItem);
	}
	auto item = this->itemAt(event->pos());
	if (item  == nullptr)
	{
    
    
		this->addTopLevelItem(curItem);
	}
	else
	{
    
    
		item->addChild(curItem);
	}
}

Import another TreeWIdget

When importing, it is mainly necessary to maintain the parent-child relationship. For example, there are three layers of nodes A, B, and C. If only A and C nodes are checked. Then when the parent-child relationship is constructed at this time, the parent node of C is A.
Implementation code

void FImportDialog::onOk(bool val)
{
    
    
	//根据勾选的层级构建导入关系
	auto topItemCount = _treeWidget->topLevelItemCount();
	_importItemList.clear();
	for (int index = 0;index<topItemCount;++index)
	{
    
    
		auto item = _treeWidget->topLevelItem(index);
		getItemChildItem(item,nullptr, _importItemList);
	}
	accept();
}

About the check of QTreeWidget

In this example, only checked and unchecked are shown. For the semi-checked state, please refer to the blog post.
https://blog.csdn.net/weixin_39308337/article/details/106353102

Code link

Because many people have a slow internet speed on GitHub. So the code is hosted on Gitee .
Note that the
code is not a complete project. There are only .h files and .cpp files. The file name is FCustomTreeWidget.h and FCustomTreeWidget.cpp
git address
https://gitee.com/zmf199785/csdncode.git The
code is in the FCustomTreeWidget directory

Guess you like

Origin blog.csdn.net/weixin_39308337/article/details/111400800