QTreeWidget internal move

Alles rund um die Programmierung mit Qt
pronti
Beiträge: 7
Registriert: 29. Januar 2008 13:46
Wohnort: Villach

QTreeWidget internal move

Beitrag von pronti »

Wie kann man verhindern, dass bei einem Move innerhalb des QtreeWidget ein Root Item in ein Child Item verschoben wird.
Child Items soll man aber schon zwischen den Root Items verschieben können.

Mein Codebeispiel:

mytreewidget.h

Code: Alles auswählen

#ifndef MYTREEWIDGET_H_
#define MYTREEWIDGET_H_

#include <QtGui>

class MyTreeWidget : public QTreeWidget
{
	Q_OBJECT

public:
	MyTreeWidget(QWidget *parent = 0);

	QStringList mimeTypes() const;	
	bool dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action); 
	Qt::DropActions supportedDropActions () const;
};

#endif /*MYTREEWIDGET_H_*/
mytreewidget.cpp

Code: Alles auswählen

#include <iostream>  
#include <QtGui>
#include "mytreewidget.h"

using namespace std;

MyTreeWidget::MyTreeWidget(QWidget *parent)
    : QTreeWidget(parent)
{
    //setRootIsDecorated(false);
	setSelectionMode(QAbstractItemView::ExtendedSelection);
	setDragEnabled(false);
	setAcceptDrops(false);
	setDropIndicatorShown(true);
	setDragDropMode(QAbstractItemView::InternalMove);
	setDragDropOverwriteMode(false);
}

QStringList MyTreeWidget::mimeTypes () const 
{
	return model()->QAbstractItemModel::mimeTypes();
}

bool MyTreeWidget::dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
{
	QModelIndex idx;
	if (parent) idx = indexFromItem(parent);
	cout << index << endl;
	if (idx.isValid()) 
	{
	    cout << "isValid" << endl;
		index=0;
	}
    return model()->QAbstractItemModel::dropMimeData(data, action , index, 0, idx);		
}

Qt::DropActions MyTreeWidget::supportedDropActions () const
{
	return Qt::CopyAction | Qt::MoveAction;
}
main.cpp

Code: Alles auswählen

#include <QtGui>
#include "mytreewidget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    
    MyTreeWidget *treeWidget = new MyTreeWidget();
    treeWidget->setColumnCount(2);
    QStringList sHeader;
    sHeader << "Letter" << "Number";
    treeWidget->setHeaderLabels(sHeader);
    QTreeWidgetItem *rootItem = new QTreeWidgetItem(treeWidget);
    rootItem->setText(0, "A");
    rootItem->setText(1, "0");
    QTreeWidgetItem *aItem = new QTreeWidgetItem(rootItem);
    aItem->setText(0, "A");
    aItem->setText(1, "0");
    aItem = new QTreeWidgetItem(rootItem);
    aItem->setText(0, "B");
    aItem->setText(1, "1");  
    aItem = new QTreeWidgetItem(rootItem);
    aItem->setText(0, "C");
    aItem->setText(1, "2");
    rootItem = new QTreeWidgetItem(treeWidget);
    rootItem->setText(0, "B");
    rootItem->setText(1, "1");
    rootItem = new QTreeWidgetItem(treeWidget);
    rootItem->setText(0, "C");
    rootItem->setText(1, "2");
    treeWidget->setWindowTitle(QObject::tr("QTreeWidget InternalMove"));
    treeWidget->show();
    
    return a.exec();
}
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Code: Alles auswählen

    int QTreeWidgetItem::childCount () const 
"RootItems" (Gruppen) haben children, "Childs" (Gruppenelemente) nicht.
So kannst du schauen was unter Deinem Drop-Cursor liegt.
Alternativ kannst Du die "Gruppen" beim Einlesen auch irgendwie mit einem Marker versehen und Du lässt Drops nur zu, wenn du den Marker findest auf dem Item unter der Maus. Wie Du den "Marker" gestaltest ist Deiner Kreativität überlassen, du kannst die QTreeWidgetItems ableiten oder irgendwas andere missbrauchen.


Diese Funktion könnte recht nützlich für Dich werden .-)

Code: Alles auswählen

   void QWidget::dragMoveEvent ( QDragMoveEvent * event ) 
macman
Beiträge: 1738
Registriert: 15. Juni 2005 13:33
Wohnort: Gütersloh
Kontaktdaten:

Beitrag von macman »

Sephral hat geschrieben:"RootItems" (Gruppen) haben children, "Childs" (Gruppenelemente) nicht.
Sehr witzig. Natürlich können Children weitere Childs haben, das ist doch gerade der Sinn eines TreeWidgets. Children haben aber ein Item als Parent, wohingegen RootItems das TreeWidget als Parent haben.

Am sinnigsten wäre es wohl QTreeWidgetItem zu überschreiben und im dragEnterEvent die Aktion zu verbieten, wenn das Parent ein QTreeWidget ist.
Die deutsche Schriftsprache ist case-sensitive. Außerdem gibt es eine Interpunktionsnorm. Wenn manch einer seine Programme genauso schlampig schreibt, wie sein Posting hier, dann sollte er es lieber bleiben lassen.
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

macman hat geschrieben: Sehr witzig. Natürlich können Children weitere Childs haben, das ist doch gerade der Sinn eines TreeWidgets.
Das ist nicht witzig, lies mal den ersten Beitrag. Pronti scheint seinen Baum genau so verwenden zu wollen. So wie ich es verstanden habe möchte er Drag&Drop lediglich zwischen "Elementen in Gruppen" und "Gruppen" erlauben, um die Elemente zwischen den Gruppen zu verschieben, daher stimmt meine Beschreibung.

Dass man einen Baum beliebig verschachteln kann ist mir auch klar.
macman
Beiträge: 1738
Registriert: 15. Juni 2005 13:33
Wohnort: Gütersloh
Kontaktdaten:

Beitrag von macman »

Sephral hat geschrieben:Das ist nicht witzig, lies mal den ersten Beitrag.
Hab ich, da steht nichts davon das der Baum nur zwei Ebenen hat.
Die deutsche Schriftsprache ist case-sensitive. Außerdem gibt es eine Interpunktionsnorm. Wenn manch einer seine Programme genauso schlampig schreibt, wie sein Posting hier, dann sollte er es lieber bleiben lassen.
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

macman hat geschrieben:
Sephral hat geschrieben:Das ist nicht witzig, lies mal den ersten Beitrag.
Hab ich, da steht nichts davon das der Baum nur zwei Ebenen hat.
Richtig, weil das auch nicht wirklich wichtig ist...

Ok, dann halt so:
Wie kann man verhindern, dass bei einem Move innerhalb des QtreeWidget ein Root Item in ein Child Item verschoben wird.
Child Items soll man aber schon zwischen den Root Items verschieben können.
* RootItem (Items die children enthalten) dürfen nicht in ChildItems (Items ohne children) verschoben werden
* ChildItems dürfen auf RootItems geschoben werden

Wobei mir Root-Items wahrscheinlich nicht das "richtige" RootItem eines Models gemeint ist, sondern einfach die erste sichtbare Ebene (die wiederum im RootItem eingehängt sind).

Unter diesen Voraussetzungen ist meine Aussage
"RootItems" (Gruppen) haben children, "Childs" (Gruppenelemente) nicht.
keinesfalls witzig, sondern ein einfacher Weg die notwendige Unterscheidung für diesen Anwendungsfall während des Drag&Drop (dragMoveEvent) vorzunehmen.
macman
Beiträge: 1738
Registriert: 15. Juni 2005 13:33
Wohnort: Gütersloh
Kontaktdaten:

Beitrag von macman »

Sephral hat geschrieben:Wobei mir Root-Items wahrscheinlich nicht das "richtige" RootItem eines Models gemeint ist, sondern einfach die erste sichtbare Ebene (die wiederum im RootItem eingehängt sind).
Ein TopLevelItem, da gehe ich auch von aus.
Sephral hat geschrieben:Unter diesen Voraussetzungen ist meine Aussage
"RootItems" (Gruppen) haben children, "Childs" (Gruppenelemente) nicht.
keinesfalls witzig, sondern ein einfacher Weg die notwendige Unterscheidung für diesen Anwendungsfall während des Drag&Drop (dragMoveEvent) vorzunehmen.
Entweder reden wir aneinander vorbei oder Du gehst davon aus das Gruppen keine Untergruppen haben können. Wenn Du prüfst ob ein Item Children hat, dann weißt Du nicht auf welcher Ebene sich dieses Item befindet. Du kannst nicht davon ausgehen das es sich um ein TopLevelItem handelt, es könnte auch ein Child mit Children sein.

Um zu prüfen ob es sich um ein TopLevelItem handelt, reicht ein einfaches

Code: Alles auswählen

if (item->parent() == pTreeWidget)
    // item ist ein TopLevelItem
Ich denke er hat jetzt genügend Anregungen um es hin zu bekommen :-)
Die deutsche Schriftsprache ist case-sensitive. Außerdem gibt es eine Interpunktionsnorm. Wenn manch einer seine Programme genauso schlampig schreibt, wie sein Posting hier, dann sollte er es lieber bleiben lassen.
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Code: Alles auswählen

Ich denke er hat jetzt genügend Anregungen um es hin zu bekommen Smile
Da bin ich mir auch sicher :-)

Aber um die Diskussion zwischen uns noch mal zu klären.
Wir sind von unterschiedlichen Szenarien ausgegangen die beide im Interpretationsrahmen der 2-Zeiligen Beschreibung liegen. Ohne mehr Informationen wie genau der Baum aufgebaut ist und was möglich sein soll beim Drag&Drop, kommen wir hier nicht mehr auf einen gemeinsamen Nenner, ohne das Ganze in ewig lange Posts ausarten zu lassen.

Hoffen wir einfach, dass für den Threadersteller der richtige Informations-Happen dabei war :-)

Ciao,
Sephral
pronti
Beiträge: 7
Registriert: 29. Januar 2008 13:46
Wohnort: Villach

Beitrag von pronti »

Vielen Dank für die Inputs. In meinem Fall ist es wirklich so, dass ich nur zwei Ebenen habe.

Wenn ich nun dragMoveEvent neu implementiere, wie komme ich vom Event auf das QWidgetItem.
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hallo,

über die die Position des Mauszeigers ( event->pos() ) kannst du das Item ausfindig machen.

Ciao,
Sephral
pronti
Beiträge: 7
Registriert: 29. Januar 2008 13:46
Wohnort: Villach

Beitrag von pronti »

Irgendwie bin ich zu blöd.

Ich verwende folgenden Code:

Code: Alles auswählen

void MyTreeWidget::dragMoveEvent(QDragMoveEvent *event)
{
	QTreeWidgetItem *item = itemAt(event->pos());
	event->ignore();
	if (item->childCount()==0)
	{
		event->setDropAction(Qt::MoveAction);
		event->accept();
	}
}
Beim Starten bekomme ich den Fehler das der referenzierte Memory nicht gelesen werden kann.
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Prüf' das Item mal gegen NULL bevor Du es verwendest...
pronti
Beiträge: 7
Registriert: 29. Januar 2008 13:46
Wohnort: Villach

Beitrag von pronti »

Ok, war mein Fehler. Jetzt läuft das Programm funktioniert aber nicht wie ich es wollte!
Ich kann jetzt jedes Item (mit oder ohne Children) auf ein Item ohne Children verschieben.
Was ich aber wollte war, dass ich ein Item mit Children nicht in ein anderes Item mit Children verschieben kann.
Die Children eines RootItem soll man aber in ein anderes RootItem verschieben können und die
RootItems sollen innerhalb des Widgets verschiebar sein.
Um das zu Implementieren muss ich daher wissen ob das gedragte Item Children hat.
Wie kann ich abfragen ob das gedragte QtreeWidgetItem Children hat?
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

pronti hat geschrieben: Jetzt läuft das Programm funktioniert aber nicht wie ich es wollte!
Es gibt sicher auch eine einfachere Lösung aber....

Wenn du das "Drag" auch selbst implementierst, kannst du entscheiden was überhaupt herumgezogen wird und hast natürlich auch alle Informationen über das Item.

* Beim mousePressEvent die Position speichern.
* In mouseMoveEvent (wenn links Taste noch gedrückt) die manhattanLength prüfen.
* Wenn's weit genug gezogen wurde, dann QDrag erzeugen
pronti
Beiträge: 7
Registriert: 29. Januar 2008 13:46
Wohnort: Villach

Beitrag von pronti »

Ich glaube ich habe eine Lösung wie ich das ganze machen kann.
Im Moment habe ich leider noch ein Problem mit

Code: Alles auswählen

if (item->parent() == pTreeWidget)
    // item ist ein TopLevelItem
'pTreeWidget' was not declared in this scope
Antworten