Drag & Drop zwischen QTreeWidget's

Alles rund um die Programmierung mit Qt
NoRulez
Beiträge: 208
Registriert: 19. Juni 2007 15:43

Drag & Drop zwischen QTreeWidget's

Beitrag von NoRulez »

Hey @all,

bin vor kurzem auf den QT Zug aufgesprungen und muss sagen es klappt soweit alles und bin sehr zufrieden damit, bis auf das Drag & Drop zwischen 2 QTreeWidget oder eben im selben QTreeWidget.

Habe auch schon in der Doku und im Forum des öfteren von diesen 4 Methoden gelesen:

Code: Alles auswählen

     void dragEnterEvent(QDragEnterEvent *event);
     void dragMoveEvent(QDragMoveEvent *event);
     void dropEvent(QDropEvent *event);
     void mousePressEvent(QMouseEvent *event);
Jedoch springt kein Breakpoint im Code an (Debug-Mode).

Im

Code: Alles auswählen

eventFilter(QObject *object, QEvent *event)
bekomme ich nur das QEvent::DragEnter - Event.

ich würde mir gerne wenn ich zum Draggen anfange einige Informationen über das Item holen und wenn danach das Drop event ausgelöst wird ebenfalls.

Kann mir da jemand helfen?

Vielen Dank im Voraus

Lg NoRulez
Zuletzt geändert von NoRulez am 26. Juni 2007 16:33, insgesamt 2-mal geändert.
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

NoRulez
Beiträge: 208
Registriert: 19. Juni 2007 15:43

Beitrag von NoRulez »

Die Doku habe ich schon gelesen, vielleicht habe ich was übersehen.

Wenn ich das ganze für das Hauptfenster implementiere

Code: Alles auswählen

void MyMainWindow::dragEnterEvent(QDragEnterEvent *event) {
}
bekomme ich auch dieses Event,

nur komme ich mit TreeViews nicht weiter :(

Muss ich da das komplette QTreeWidget subclassen?
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Nein, aber du must Drag & Drop in der View freischalten.

Aus der Doku, gilt natürlich auch für eine View:

Code: Alles auswählen

QListWidget *listWidget = new QListWidget(this);
 listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
 listWidget->setDragEnabled(true);
 listWidget->setAcceptDrops(true);
 listWidget->setDropIndicatorShown(true);
NoRulez
Beiträge: 208
Registriert: 19. Juni 2007 15:43

Beitrag von NoRulez »

Das habe ich ja alles freigeschalten, ich möchte nurmehr auf die DragEnter usw. reagieren können.

Im Moment kann ich die Items kopieren, ohne das ich jedoch noch eine Funktion implementiert habe. UND das ist mein Problem. Ich muss wenn ich daten per drag and drop ziehe auch im hintergrund noch andere sachen machen. diese kann ich jedoch nur wenn ich die Events abfangen kann.

Lg
macman
Beiträge: 1738
Registriert: 15. Juni 2005 13:33
Wohnort: Gütersloh
Kontaktdaten:

Beitrag von macman »

NoRulez hat geschrieben:Muss ich da das komplette QTreeWidget subclassen?
Ja. Ist nicht soviel wie es aussieht und Du hast hinterher die volle Kontrolle. Mach es, Du wirst es nicht bereuen.
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.
@udisello
Beiträge: 50
Registriert: 19. März 2007 14:58
Wohnort: Sachsen

Beitrag von @udisello »

Hallo,

leite doch einfach das QTreeWidget ab und überschreibe dort deine Events, dann kannst du auch selbst festlegen. wann und wie das Drag Event startet und welche Daten übertragen werden. Nicht viel Aufwand, aber großer Nutzen.

im Header z.B.:

Code: Alles auswählen

void mousePressEvent( QMouseEvent* pEvent );
void mouseMoveEvent( QMouseEvent* pEvent );
void dropEvent( QDropEvent* pEvent );
void dragEnterEvent( QDragEnterEvent* pEvent );
void dragMoveEvent( QDragMoveEvent* pEvent );
und in deiner cpp:

Code: Alles auswählen

void YourClass::mousePressEvent( QMouseEvent* pEvent )
{
  if( pEvent->button() == Qt::LeftButton )
  {
    m_StartPoint = pEvent->pos();
  }  
  QTreeWidget::mousePressEvent( pEvent );
}

void YourClass::mouseMoveEvent( QMouseEvent* pEvent )
{
  if( pEvent->buttons() & Qt::LeftButton )
  {
    int iDistance = ( pEvent->pos() - m_StartPoint ).manhattanLength();
    if( iDistance >= QApplication::startDragDistance() )
      StartDrag();
  }
  QTreeWidget::mouseMoveEvent( pEvent );
}

void YourClass::StartDrag()
{
    QMimeData* pMimeData = new QMimeData;
    pMimeData->setText( "whatyouwant" );
    QDrag* pDrag = new QDrag( this ); 
    pDrag->setMimeData( pMimeData );
    if( pDrag->start( Qt::CopyAction ) )
      DoSomething();
}

void YourClass::dropEvent( QDropEvent* pEvent )
{
    if( pEvent->mimeData()->hasText() )
    {
      DoSomething();
      pEvent->setDropAction( Qt::CopyAction );
      pEvent->accept();
    }
}

void YourClass::dragEnterEvent( QDragEnterEvent* pEvent )
{
  //hier Bedingungen, wann Drag akzepiert wird
  pEvent->setDropAction( Qt::CopyAction );
  pEvent->accept();
}

void YourClass::dragMoveEvent( QDragMoveEvent* pEvent )
{
  //hier Bedingungen, wann Drag akzepiert wird    
  pEvent->setDropAction( Qt::CopyAction );
  pEvent->accept();
}
MfG @udisello

Qt Version 4.3.0, MS VS 2005
NoRulez
Beiträge: 208
Registriert: 19. Juni 2007 15:43

Beitrag von NoRulez »

Vielen Dank,

nur macht es einen Unterschied wenn ich die QTreeWidgets mit dem Designer erzeugt habe?
Theoretisch wird dann die Sub-Klasse ja nicht aufgerufen oder?
Würde gerne beim Designer bleiben. Aber wie gesagt bin noch neu bei QT, vielleicht geht das ja irgendwie. :roll:

Lg
macman
Beiträge: 1738
Registriert: 15. Juni 2005 13:33
Wohnort: Gütersloh
Kontaktdaten:

Beitrag von macman »

Ja, das geht. Im Designer Rechtsklick auf dein TreeWidget, 'Als Platzhalter für benutzerdefinierte Klasse', und in dem Dialog gibst Du dann nur noch deinen Klassennamen und die Header-Datei an.
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.
NoRulez
Beiträge: 208
Registriert: 19. Juni 2007 15:43

Beitrag von NoRulez »

In der Methode

Code: Alles auswählen

void dropEvent(QDropEvent* pEvent);
kann man ja mittels

Code: Alles auswählen

pEvent->source();
pEvent->target();
die Source und Target Widget's bekommen mein Problem ist jetzt nur das das Target nicht meinem wirklichen TreeWidget entspricht :(

Sprich ich übergebe im Konstruktor meine 2 TreeWidgets (tree1 und tree2)
theoretisch müsste ja eines der beiden anspringen

Code: Alles auswählen

if(pEvent->target() == tree1)
   DoSomthing1();
else if(pEvent->target() == tree2)
   DoSomthing2();
Wie finde ich am besten raus von wo nach wo ich dragge?

Lg NoRulez[/code]
@udisello
Beiträge: 50
Registriert: 19. März 2007 14:58
Wohnort: Sachsen

Beitrag von @udisello »

Nur nochmal die Frage, Du erstellst dir ein Widget und legst dort die zwei TreeWidgets ( deine abgeleitete Klasse ) an? In der abgeleiteten Klasse hast Du dann z.B. das dropEvent, welches ausgelöst wird, wenn du ein Element auf das TreeWidget ziehst. Dann einfach:

Code: Alles auswählen

void YourClass::dropEvent( QDropEvent *pEvent )
{
  YourClass *pSource = qobject_cast< YourClass* >( pEvent->source() );
  if( pSource && pSource != this )
  {
    DoSomething();
    pEvent->accept();
  }
}
Wie Du siehst, hast Du dann einen Pointer auf die Quelle (pSource) und einen auf das Ziel (this).
Berichtige mich bitte wer es besser weiß, aber QDropEvent hat kein target()??? Es gibt nur
QWidget * QDrag::target () const
Returns the target of the drag and drop operation. This is the widget where the drag object was dropped.
Das kannst Du dann in der Funktion

Code: Alles auswählen

void YourClass::StartDrag()
{
    QMimeData* pMimeData = new QMimeData;
    pMimeData->setText( "whatyouwant" );
    QDrag* pDrag = new QDrag( this );
    pDrag->setMimeData( pMimeData );
    if( pDrag->start( Qt::CopyAction ) )
       DoSomething( with pDrag->target()  );
} 
abfangen
MfG @udisello

Qt Version 4.3.0, MS VS 2005
NoRulez
Beiträge: 208
Registriert: 19. Juni 2007 15:43

Beitrag von NoRulez »

Sorry meinte es eh so

Code: Alles auswählen

void YourClass::StartDrag()
{
    QMimeData* pMimeData = new QMimeData;
    pMimeData->setText( "whatyouwant" );
    QDrag* pDrag = new QDrag( this );
    pDrag->setMimeData( pMimeData );
    if( pDrag->start( Qt::CopyAction ) )
       DoSomething( with pDrag->target()  ); // pDrag->target() ist weder tree1 noch tree2
}
pDrag->target() ist weder tree1 noch tree2

ich frage das ganze so ab

Code: Alles auswählen

if(pDrag->target() == (QWidget*)this->tree1)
      BLABLABLA_1
else if(pDrag->target() == (QWidget*)this->tree2)
      BLABLABLA_2
Lg NoRulez
NoRulez
Beiträge: 208
Registriert: 19. Juni 2007 15:43

Beitrag von NoRulez »

OK ich habe das ganze nochmals angeschaut, pDrag->target() ist NULL wieso bekomme ich da nicht den Drag-Target?

ich habe für beide Tree's folgendes im Hauptfenster eingestellt:

Code: Alles auswählen

tree1->setSelectionMode(QAbstractItemView::SingleSelection);
tree1->setDragEnabled(true);
tree1->setAcceptDrops(true);
tree1->setDropIndicatorShown(true);

tree2->setSelectionMode(QAbstractItemView::SingleSelection);
tree2->setDragEnabled(true);
tree2->setAcceptDrops(true);
tree2->setDropIndicatorShown(true);
Mit QAbstractItemView::ExtendedSelection funktioniert es auch nicht

Lg NoRulez
@udisello
Beiträge: 50
Registriert: 19. März 2007 14:58
Wohnort: Sachsen

Beitrag von @udisello »

Also ich glaube, wir reden noch aneinander vorbei. Du sollst eine neue Klasse erstellen, die du von QTreeWidget ableitest. Dort überschreibst du die Funktionen, die ich gepostet habe. In deinem MainWindow erstellst du dir dann zwei Objekte( tree1, tree2 ) deiner neuen Klasse. Dann brauchst du theoretisch das target() gar nicht mehr, da das dropEvent an "zwei unterschiedlichen Stellen" eintritt.
MfG @udisello

Qt Version 4.3.0, MS VS 2005
NoRulez
Beiträge: 208
Registriert: 19. Juni 2007 15:43

Beitrag von NoRulez »

So jetzt ist alles klar und funktioniert prima

Danke vielmals

Habe nur noch ein winziges Problem.

Beim Drag and Drop scheint es von haus aus so zu sein das er einen Blauen balken als Drag Image hat. Kann man den irgendwie überschreiben/zeichnen?

Lg NoRulez
Antworten