10

I have a QTreeWidget which displays a single root node and one level of child nodes only. I need to permit the re-ordering of the child nodes. They must never be re-parented.

This is how I enable the dragging of items in the QTreeWidget :

ui->levelElements->setSelectionMode(QAbstractItemView::SingleSelection);
ui->levelElements->setDragEnabled(true);
ui->levelElements->viewport()->setAcceptDrops(true);
ui->levelElements->setDropIndicatorShown(true);
ui->levelElements->setDragDropMode(QAbstractItemView::InternalMove);

The root item is inserted like this :

pItem = new QTreeWidgetItem(ui->levelElements);
pItem->setText(0, node.firstChild().nodeValue());
pItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled);

When I insert a child into the view, it is declared like this :

pItem = new QTreeWidgetItem();
pItem->setText(0, strFileName);
pItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
pTreeRoot->addChild(pItem);

At this point, I am able to drag a child item and "re-insert" it in the list of child items. I can also move it to the root level - which I do not want.

I am using QT Creator v3 and so the QTreeWidget is within my UI definition file.

Have I missed something here ?

Maxim Makhun
  • 2,197
  • 1
  • 22
  • 26
Simon
  • 2,208
  • 4
  • 32
  • 47
  • Maybe this will help: http://www.qtcentre.org/threads/32354-Qt-ItemIsDropEnabled-ignored-in-dragDropMode-QAbstractItemView-InternalMove – Ferenc Deak Jan 22 '14 at 13:17

1 Answers1

8

For example you can override: virtual void dropEvent(QDropEvent * event)

#include <QApplication>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QDropEvent>

class TreeView: public QTreeWidget
{
public:
  TreeView()
  {
    resize(200, 300);

    setSelectionMode(QAbstractItemView::SingleSelection);
    setDragEnabled(true);
    viewport()->setAcceptDrops(true);
    setDropIndicatorShown(true);
    setDragDropMode(QAbstractItemView::InternalMove);

    QTreeWidgetItem* parentItem = new QTreeWidgetItem(this);
    parentItem->setText(0, "Test");
    parentItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled);

    for(int i = 0; i < 10; ++i)
    {
      QTreeWidgetItem* pItem = new QTreeWidgetItem(parentItem);
      pItem->setText(0, QString("Number %1").arg(i) );
      pItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
      pItem->addChild(pItem);
    }
  }

private:
  virtual void  dropEvent(QDropEvent * event)
  {
    QModelIndex droppedIndex = indexAt( event->pos() );

    if( !droppedIndex.isValid() )
      return;

    QTreeWidget::dropEvent(event);
  }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    TreeView widget;
    widget.show();

    return a.exec();
}
Igor
  • 1,029
  • 9
  • 21
  • thank you for your information. However, I don't know how I can change the class intialised by the UI from the designer file (remember I am using Qt Creator). Is there a way around this ? – Simon Jan 22 '14 at 15:47
  • You can promote standard QTreeWidget to TreeView in Qt Creator(http://www.youtube.com/watch?v=Yt-YCxgEnyw) – Igor Jan 22 '14 at 16:24
  • 1
    Exists more ugly solution(workaround inheritance): installEventFilter for your QTreeView object and catch there QDropEvent. – Igor Jan 22 '14 at 16:36