如何解决QTreeWidgetItem的拖放操作无法正常工作
我重新划分了QTreeWidget
的子类,以便重新实现protected
和drag
的{{1}}功能,以便拖放drop
的父级和子级。
几乎可以正常运行,并且问题是,一旦我尝试拖放孩子或父母,我将其删除后会立即删除它们。 可以在here中找到源代码,以备不时之需。
此外,如果我尝试拖放父级,很遗憾它不会移动并且什么也没发生。
请参见下文对孩子的奇怪影响:
我将子项“ Original”拖到“ Sample”下,此过程似乎可以正常工作:
在删除“原始”后,您可以看到索引似乎在那里,但似乎已被部分擦除:
我不确定到底发生了什么,为什么孩子似乎没有完全正确地掉落,以及为什么父母实际上没有动弹。
下面是最小可验证示例的代码:
mainwindow.h
QTreeWidget
mainwindow.cpp
#include <QMainWindow>
class QTreeWidget;
class QTreeWidgetItem;
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QTreeWidgetItem *createItem(const QString &name,const QString &iconPath);
private:
Ui::MainWindow *ui;
QTreeWidget *widget;
QString m_Name;
QString m_Path;
};
#endif // MAINWINDOW_H
maphelpers.h
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->treeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
ui->treeWidget->setDragEnabled(true);
ui->treeWidget->viewport()->setAcceptDrops(true);
ui->treeWidget->setDropIndicatorShown(true);
ui->treeWidget->setDragDropMode(QAbstractItemView::InternalMove);
auto *top1 = createItem("Images","/home/ui/qrc/laserscan.png");
auto *top2 = createItem("Path","/home/ui/qrc/laserscan.png");
top1->addChild(createItem("Original","/home/ui/qrc/laserscan.png"));
top1->addChild(createItem("Sample","/home/ui/qrc/laserscan.png"));
top2->addChild(createItem("Left Side","/home/ui/qrc/laserscan.png"));
top2->addChild(createItem("Right Side","/home/ui/qrc/laserscan.png"));
ui->treeWidget->addTopLevelItems({ top1,top2 });
// Below I am assigning to each parent/children a checkbox
const int n_tops = ui->treeWidget->topLevelItemCount();
for(int a = 0; a<n_tops; ++a) {
const int n_children = ui->treeWidget->topLevelItem(a)->childCount();
qtreewidgetitem_assign_qcheckbox(ui->treeWidget,ui->treeWidget->topLevelItem(a));
for(int b = 0; b<n_children; ++b) {
qtreewidgetitem_assign_qcheckbox(ui->treeWidget,ui->treeWidget->topLevelItem(a)->child(b));
}
}
}
MainWindow::~MainWindow()
{
delete ui;
}
QTreeWidgetItem *MainWindow::createItem(const QString &name,const QString &iconPath)
{
auto *item = new QTreeWidgetItem(QStringList{name});
item->setIcon(0,QIcon(iconPath));
return item;
}
maphelpers.cpp
#include <QTreeWidget>
#include <QTreeWidgetItem>
void qtreewidgetitem_assign_qcheckbox(QTreeWidget *tree_widget,QTreeWidgetItem *tree_item);
#endif // MAPHELPERS_H
在我如何归类为#include <QTreeWidget>
void qtreewidgetitem_assign_qcheckbox(QTreeWidget *tree_widget,QTreeWidgetItem *tree_item)
{
MyCheckBoxMap *myCheckBoxMap = new MyCheckBoxMap(tree_item);
tree_widget->setItemWidget(tree_item,MAP_COLUMN,myCheckBoxMap);
}
的下面:
customtreewidget.h
QTreeWidget
customtreewidget.cpp
#include <QTreeWidget>
class CustomTreeWidget : public QTreeWidget
{
public:
CustomTreeWidget(QWidget *parent = Q_NULLPTR);
protected:
void dragEnterEvent(QDragEnterEvent *event) override;
void dropEvent(QDropEvent *event) override;
private:
QTreeWidgetItem *draggedItem;
};
#endif // CUSTOMTREEWIDGET_H
我到目前为止所做的和我尝试过的:
1)根据官方文档,可以使用QTreeWidgetItemIterator Class,我尝试过这种方式,实际上您可以在我的最初实现想法下看到,但这没有真的带我到任何地方:
CustomTreeWidget::CustomTreeWidget(QWidget *parent)
{
QTreeWidgetItem* parentItem = new QTreeWidgetItem();
parentItem->setText(0,"Test");
parentItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled);
int num_rows = topLevelItemCount();
for(int i = 0; i < num_rows; ++i)
{
int nChildren = topLevelItem(i)->childCount();
QTreeWidgetItem* pItem = new QTreeWidgetItem(parentItem);
for(int j = 0; j < nChildren; ++j) {
pItem->setText(0,QString("Number %1").arg(i) );
pItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
pItem->addChild(pItem);
topLevelItem(i)->child(j);
}
}
}
void CustomTreeWidget::dragEnterEvent(QDragEnterEvent *event)
{
draggedItem = currentItem();
QTreeWidget::dragEnterEvent(event);
}
void CustomTreeWidget::dropEvent(QDropEvent *event)
{
QModelIndex droppedIndex = indexAt(event->pos());
if(!droppedIndex.isValid()) {
return;
}
if(draggedItem) {
QTreeWidgetItem *mParent = draggedItem->parent();
if(mParent) {
if(itemFromIndex(droppedIndex.parent()) != mParent)
return;
mParent->removeChild(draggedItem);
mParent->insertChild(droppedIndex.row(),draggedItem);
}
}
}
2)在官方文档中进行了进一步研究之后,我决定采用QMapIterator Class来解决该问题,因此我希望保留最初构造的构造函数,并认为通过{{ 1}}的意思是用另一种方式重写构造函数,基本上是下面的实现思想,但不想通过这种方式:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto *top1 = createItem("Images","/home/ui/qrc/laserscan.png");
top1->addChild(createItem("Original","/home/ui/qrc/laserscan.png"));
top2->addChild(createItem("Left Side","/home/ui/qrc/laserscan.png"));
ui->treeWidget->addTopLevelItems({ top1,top2 });
const int n_tops = ui->treeWidget->topLevelItemCount();
// Below I am assigning to each parent/children a checkbox
for(int a = 0; a<n_tops; ++a) {
const int n_children = ui->treeWidget->topLevelItem(a)->childCount();
qtreewidgetitem_assign_qcheckbox(ui->treeWidget,ui->treeWidget->topLevelItem(a)->child(b));
}
}
QTreeWidgetItem *parentItem = Q_NULLPTR;
QTreeWidgetItem *childItem = Q_NULLPTR;
QTreeWidgetItemIterator it(ui->treeWidget);
while (*it) {
parentItem = new QTreeWidgetItem(ui->treeWidget);
//parentItem->setText(0,it.key());
foreach (const auto &str,it) {
childItem = new QTreeWidgetItem;
childItem->setText(0,str);
parentItem->addChild(childItem);
}
}
}
3)经过更多的研究,我发现了this source和this other source这两个元素(尤其是最后一篇)非常有用,可作为实现该子类的指导。 QMap
。
现在,我正试图找出原因,尽管我做了很多尝试,却还是遇到了困扰,但是我仍然获得了90%的可运行应用程序,因此,为什么缺少它?
感谢您提供有关如何解决此问题的指导。
解决方法
我认为复选框正在处理鼠标事件,并且不要让事件进入项目。要获得所需的行为,您应该删除此部分:
const int n_tops = ui->treeWidget->topLevelItemCount();
for(int a = 0; a<n_tops; ++a) {
const int n_children = ui->treeWidget->topLevelItem(a)->childCount();
qtreewidgetitem_assign_qcheckbox(ui->treeWidget,ui->treeWidget->topLevelItem(a));
for(int b = 0; b<n_children; ++b) {
qtreewidgetitem_assign_qcheckbox(ui->treeWidget,ui->treeWidget->topLevelItem(a)->child(b));
}
}
在createItem()
函数中:
QTreeWidgetItem *MainWindow::createItem(const QString &name,const QString &iconPath)
{
auto *item = new QTreeWidgetItem(QStringList{name});
item->setCheckState(0,Qt::Unchecked);
item->setIcon(0,QIcon(iconPath));
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
return item;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。