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. customContextMenuRequested
Just 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 dropEvent
processing 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