QTreeView Remove and Re-Insert childitem from parent?
-
So I have a qtreeview and obviously at some point some items are parents of other child items. Moving child items between parents does work fine but im not able to move child items outside its parent into the main view. Any idea on how to do this?
-
@StudentScripter said in QTreeView Remove and Re-Insert childitem from parent?:
not able to move child items outside its parent into the main view
I don't know what you mean here. What is the "main view" you speak of?
-
@JonB So basically i can move my items between my parents/groups, but i can't move my items completely out of any parents/groups.
At the beginning all items are on the same layer = all items have no childitems.
-->than i move one item below another, it gets its child.
-->i try to move the children back so that it isn't the child anymore but this doesn't work. -
@StudentScripter
Could you show screenshot(s) so that we see (a) where the item was initially when you dragged it and (b) where you are trying to drag the item to now? -
@jsulm
I have not tried anything :) If there is a root node to which the OP wants to drag to make child I would expect that to work, like to any other parent? As for dragging to make brand new root node I don't know how that would be supported/what you would need to do? So let's start by seeing it failing to create a child on an existing root node? -
Sorry for the bad explanation, im attaching screenshots here. May this helps. :)
Also thanks for trying to help me. <31. At the beginning i have this: (all item have no child items)
2. I move the Child node into the Parent using drag and drop:
3. I want to move the Child node back - out of the Parent so that it is like in picture one (thats where i can't find a way to make it work)
Here is the current code for my Qtreeview:
#include "ViewLayerList.h" #include <QHBoxLayout> #include <QCheckBox> #include <QLabel> #include "ViewLayerLineEdit.h" #include <QMouseEvent> #include "resizablepixmapitem.h" #include "SignalManager.h" #include <QHeaderView> #include <QPushButton> #include "ViewLayerCustomItem.h" #include <QTimer> #include <QApplication> ViewLayerList::ViewLayerList(CustomGraphicsScene *scene, QWidget *parent) : QTreeView{parent}, scene_durchgereicht(scene) { // Ändern Sie den Abstand zwischen den Items und der vertikalen Scrollbar setViewportMargins(0, 0, 50, 0); // Passen Sie den rechten Rand (20) an Ihre Anforderungen an //Versteckt die sinnlose Kopfzeile setHeaderHidden(false); setRootIsDecorated(true); setMouseTracking(true); //setFocusPolicy(Qt::StrongFocus); //setEditTriggers(QAbstractItemView::AllEditTriggers); mydelegate = new ViewLayerItemDelegate(this); model = new ViewLayerStandartItemModel(10,1,this); for(int row = 0; row < 10; ++row) { for(int col = 0; col < 1; ++col) { QModelIndex index = model->index(row, col, QModelIndex()); model->setData(index, ""); model->setData(index, true, ViewLayerStandartItemModel::CanHaveChildrenRole); // Dieses Element kann keine Kinder haben if(row == 0 && col == 0) { model->setData(index, false, ViewLayerStandartItemModel::CanHaveChildrenRole); // Dieses Element kann keine Kinder haben } } } this->setModel(model); this->setItemDelegate(mydelegate); this->setDragDropMode(QAbstractItemView::InternalMove); this->setSelectionMode(QAbstractItemView::ExtendedSelection); this->setDragEnabled(true); this->setAcceptDrops(true); this->setDropIndicatorShown(true); } void ViewLayerList::drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const { if (selectionModel()->isSelected(index)) { // Zeichnen Sie den Einzugsbereich (Indentation) mit Ihrer gewünschten Farbe painter->fillRect(options.rect, QColor(173, 216, 230)); // "lightblue" Hervorhebungsfarbe*/ } QTreeView::drawRow(painter, options, index); // Rufen Sie die Basisimplementierung auf, um die Standardzeichnung durchzuführen } void ViewLayerList::mousePressEvent(QMouseEvent *event) { // Ermitteln Sie den Index des Items unter der Maus QModelIndex index = indexAt(event->pos()); if (!index.isValid()) { // Wenn kein gültiges Item unter der Maus ist, rufen Sie die Basisklasse-Methode auf und kehren Sie zurück QTreeView::mousePressEvent(event); return; } // Holen Sie sich die ausgewählten Indizes QModelIndexList indexes = this->selectionModel()->selectedIndexes(); qDebug() << "Selected Index: " <<indexes; if (indexes.size() > 1) { OnlyOneItemSelected = false; }else{ qDebug() << "Index ist 1"; OnlyOneItemSelected = true; } const QRect itemRect = this->visualRect(index); //QPointF ClickPosition = event->position(); // press position in item's coords QPointF BetterClickPos = event->position() - itemRect.topLeft(); // press position in item's coords qDebug() << "(Better) TREE View MousePress: " << BetterClickPos; qDebug() << "TREE Item Rect: " << itemRect; if(BetterClickPos.x() >= itemRect.width()-35 && BetterClickPos.x() <= itemRect.width()-20) { // Zugriff auf das Modell ViewLayerStandartItemModel *modelObj = qobject_cast<ViewLayerStandartItemModel*>(this->model); // Überprüfen Sie, ob das Modell korrekt gecastet wurde if(modelObj) { if(OnlyOneItemSelected == false) { for (const QModelIndex &index : indexes) { bool value = index.data(Qt::CheckStateRole).toBool(); modelObj->setData(index, !value, Qt::CheckStateRole); } }else{ bool value = index.data(Qt::CheckStateRole).toBool(); modelObj->setData(index, !value, Qt::CheckStateRole); } mydelegate->setOtherIndexClicked(true); } //Returned ohne das mouseEvent zu handeln dadurch wird ein DoubleClicken über //Der Checkbox verhindert return; } QTreeView::mousePressEvent(event); mydelegate->setOtherIndexClicked(false); } void ViewLayerList::dropEvent(QDropEvent *event) { QModelIndex sourceIndex = indexAt(event->pos()); QModelIndex destinationIndex = currentIndex(); // Der Index, in den Sie das Element verschieben möchten qDebug() << "SourceIndex: " << sourceIndex; qDebug() << "Destination Index: " << destinationIndex; // Rufen Sie die Basisklasse-Methode auf, um die Standard-Verarbeitung fortzusetzen QTreeView::dropEvent(event); }
And here is the code for my QStandartItemModel:
#include "ViewLayerList.h" ViewLayerStandartItemModel::ViewLayerStandartItemModel(int rows, int columns, QObject *parent) : QStandardItemModel(rows, columns, parent) { } Qt::ItemFlags ViewLayerStandartItemModel::flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = QStandardItemModel::flags(index); // Überprüfen Sie, ob der Index zu einem Ihrer speziellen Delegaten gehört if (!data(index, CanHaveChildrenRole).toBool()) { return defaultFlags & ~Qt::ItemIsDropEnabled; // Entfernen Sie das ItemIsDropEnabled-Flag } return defaultFlags; }
If there are any more questions please ask.
-
This seems to work kinda like i want it to:
// Zugriff auf das Modell QStandardItemModel *modelObj = dynamic_cast<QStandardItemModel*>(this->model); // Überprüfen Sie, ob das Modell korrekt gecastet wurde if(modelObj) { QStandardItem* itemClicked = modelObj->itemFromIndex(index); QModelIndex parentIndex = index.parent(); QStandardItem* parentItem = modelObj->itemFromIndex(parentIndex); if(parentItem) { // clicked item has a parent int row = itemClicked->row(); QList<QStandardItem*> items = parentItem->takeRow(row); // remove the item from its parent modelObj->invisibleRootItem()->appendRow(items); // add the item to the root of the model } }
Only problem i somehow have to encorporate this into the drop event now, but will have a look at that.
-
@StudentScripter
The important thing then is: you are not saying you cannot drag an item to make it the child of an existing root item. You are saying you cannot find a way to make the dragged item a new root item. That is your sole issue.Not that I have an answer. But I can see one problem is: where exactly do you want to drop the item such that it will be treated as a new root item? It is not clear to me where on that picture you think you should drag to/drop on that should be treated as this operation? The problem may be that the treeview deals with drops onto onto existing nodes but does not have a mechanism for dealing with drops "elsewhere".
-
@StudentScripter
No, the whole point/trouble is that there is no parent to drag it onto when you have said you want it to be top-level/root/no parent. You want to drag it onto theinvisibleRootItem()
, and of course that is not visible on the treeview. hence the issue. -
@JonB na may i explained it wrong. When i drag one item below another item it gets it's child item right? So therefore it has a parent.
Than you drag the child item on this parent item. In this step the item should be moved out of the parent and be appended to the invisibleRootItem() -
QTreeWidget can do what you want so take a look in it's implementation - maybe it helps.
-
@Christian-Ehrlicher Im using a qtreeview and have to use qtreeview not qtreewidget. But no problem your help is appreciated. :)
-
@StudentScripter said in QTreeView Remove and Re-Insert childitem from parent?:
Im using a qtreeview and have to use qtreeview not qtreewidget.
I know - I just told you that QTreeWidget can do what you want and you can inspect QTreeWidget source code to see how it is done.
-
@Christian-Ehrlicher Now i understand nevermind. :)
-
@Christian-Ehrlicher So i got this working pretty great, but somehow when i move 2 items at ones out of it's parent only the data of one item gets copied over to both new inserted items:
This i the start situation (1 parent with 2 child items):
Than i select both items and drop than onto their parent item:
After dropping i get two items named identically, but instead they should keep their data:
Here is my code:
void ViewLayerList::dragEnterEvent(QDragEnterEvent *event) { // Ermitteln Sie den Index des Items unter der Maus QModelIndex index = indexAt(event->position().toPoint()); if (!index.isValid()) { // Wenn kein gültiges Item unter der Maus ist, rufen Sie die Basisklasse-Methode auf und kehren Sie zurück QTreeView::dragEnterEvent(event); return; } // Zugriff auf das Modell QStandardItemModel *modelObj = dynamic_cast<QStandardItemModel*>(model); // Überprüfen Sie, ob das Modell korrekt gecastet wurde if (modelObj) { // Vor jedem Drag-Event leeren Sie die Parent-Index-Liste parentChildMap.clear(); selectedIndexList.clear(); // Sammeln Sie die Parent-Indizes für ausgewählte Items QModelIndexList selectedIndexes = selectionModel()->selectedIndexes(); for (const QModelIndex& selectedIndex : selectedIndexes) { QModelIndex parentIndex = selectedIndex.parent(); // Fügen Sie das Paar zur Map hinzu parentChildMap.insert(selectedIndex, parentIndex); // Fügen Sie den ausgewählten Index zur Liste hinzu selectedIndexList.append(selectedIndex); // Zugriff auf das ausgewählte Element und fügen Sie es zur Liste hinzu QStandardItem* selectedItem = modelObj->itemFromIndex(selectedIndex); } int selectedItemCount = selectedIndexes.count(); qDebug() << "Anzahl der ausgewählten Items: " << selectedItemCount; // Nachdem Sie die Map gefüllt haben... for(auto it = parentChildMap.constBegin(); it != parentChildMap.constEnd(); ++it) { qDebug() << "Child: " << it.key().data() << ", Parent: " << it.value().data(); } } QTreeView::dragEnterEvent(event); } void ViewLayerList::dropEvent(QDropEvent *event) { // Ermitteln Sie den Index des Items unter der Maus QModelIndex index = indexAt(event->position().toPoint()); if (!index.isValid()) { QTreeView::dropEvent(event); return; } QModelIndex destinationIndex = indexAt(event->position().toPoint()); // Rufen Sie die Basisklasse-Methode auf, um die Standard-Verarbeitung fortzusetzen QTreeView::dropEvent(event); // Zugriff auf das Modell QStandardItemModel *modelObj = dynamic_cast<QStandardItemModel*>(this->model); // Überprüfen Sie, ob das Modell korrekt gecastet wurde if(modelObj) { qDebug() << "destinationIndex data: " << destinationIndex.data(); // Überprüfen Sie, ob der Zielindex das Wurzelelement als Elternteil hat bool isDestinationRoot = (destinationIndex.parent() == QModelIndex()); qDebug() << "DestinationHasROOT as parent: " << isDestinationRoot; // Nachdem Sie das Ereignis verarbeitet haben... for (const QModelIndex& selectedIndex : selectedIndexList) { // Holen Sie sich den Elternindex für das ausgewählte Element QModelIndex parentIndex = parentChildMap.value(selectedIndex); // Zugriff auf das Elternelement QStandardItem* parentItem = modelObj->itemFromIndex(parentIndex); // Vergleichen Sie die Daten des Elternindex mit den Daten des Zielindex if(parentIndex.data() == destinationIndex.data() && isDestinationRoot) { // Entfernen Sie das Kind-Element aus seinem Elternelement int row = 0; QList<QStandardItem*> items = parentItem->takeRow(row); //THIS COMMET BEHAVES REALLY STRANGE WHEN I REMOVE IT //SEE THE PICTURE BELOW qDebug() << "ItemList:" << parentItem->takeRow(row); // Bestimmen Sie die Position, an die das Element verschoben werden soll int newPosition = parentIndex.row() + 1; // Fügen Sie das Kind-Element an der neuen Position zum invisibleRootItem hinzu modelObj->invisibleRootItem()->insertRow(newPosition, items); } } } }
There also is this one comment, everytime i try to remove it,my items get only copied in the dragging process but not removed anymore, so i end up with copies like this: (if the comment is there everything works fine, i found that strange)
I only commented out the comment:
//qDebug() << "ItemList:" << parentItem->takeRow(row);
-
P Pl45m4 referenced this topic on