QTreeWidgetItem的拖放操作无法正常工作

如何解决QTreeWidgetItem的拖放操作无法正常工作

我重新划分了QTreeWidget的子类,以便重新实现protecteddrag的{​​{1}}功能,以便拖放drop的父级和子级。

几乎可以正常运行,并且问题是,一旦我尝试拖放孩子或父母,我将其删除后会立即删除它们。 可以在here中找到源代码,以备不时之需。

此外,如果我尝试拖放父级,很遗憾它不会移动并且什么也没发生。

请参见下文对孩子的奇怪影响:

我将子项“ Original”拖到“ Sample”下,此过程似乎可以正常工作:

ddrop

在删除“原始”后,您可以看到索引似乎在那里,但似乎已被部分擦除:

ddrop2

我不确定到底发生了什么,为什么孩子似乎没有完全正确地掉落,以及为什么父母实际上没有动弹。

下面是最小可验证示例的代码:

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 sourcethis 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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-