Archiv verlassen und diese Seite im Standarddesign anzeigen : Drag and Drop
Hallo Leute,
ich möchte per Drag and Drop ein Fenster öffnen und bin nicht sicher, wie ich es realisieren soll. Ich habe mir verschiedene Beispiele angesehen, aber nichts Passendes gefunden.
Was ich machen möchte:
Ich habe auf der linken Seite des Programmes einen Baum (QListView) mit Dateinamen. Wenn ich einen Doppelklick auf ein Item mache, wird rechts ein Fenster geöffnet, die entsprechende Datei eingelesen und Daten im Fenster gesetzt. Nun möchte ich denselben Effekt per Drag and Drop erzeugen. Ich möchte also auf ein Item klicken, es festhalten, nach rechts ziehen und dort loslassen. Dann soll sich das entsprechende Fenster öffnen. Kann man das irgendwie machen?
Ich habe es schon mit QDropEvent etc. versucht, aber ich weiß gar nicht, wie die Events überhaupt ausgelöst werden. Ich benutze item->setDragEnabled( true );" , aber es passiert nichts.
Muss ich eine eigene Klasse von QListView ableiten, um QDragObject * QListView::dragObject () [virtual protected] selbst zu schreiben? Kann ich darin einfach eine Funktion aufrufen?
Vielen Dank,
Kirstin
anda_skoa
23-08-2005, 09:52
ich möchte per Drag and Drop ein Fenster öffnen und bin nicht sicher, wie ich es realisieren soll. Ich habe mir verschiedene Beispiele angesehen, aber nichts Passendes gefunden.
Ein extra Fenster öffnen oder in einem vorhandenen Fenster etwas neues anzeigen?
Muss ich eine eigene Klasse von QListView ableiten, um QDragObject * QListView::dragObject () [virtual protected] selbst zu schreiben?
Ja, am besten eine Instanz von QUriDrag erzeugen da du ja Dateinamen hast.
Kann ich darin einfach eine Funktion aufrufen?
Das macht QListView selbst.
Das DropEvent ist erst im Empfänger relevant, d.h. der bekommt zuerst ein DragEnter Event, dann DragMoveEvents und zum Schluß eben potentiell ein DropEvent.
Ciao,
_
Hallo anda_skoa,
danke für deine Antwort.
Ich möchte beides: wenn noch kein Fenster geöffnet ist, möchte ich ein Fenster öffnen, wenn schon eins geöffnet ist, Daten hinzufügen. Geht das?
Sieht man das Ereignis eigentlich, wird also irgendwas auch optisch verschoben?
Schöne Grüße,
Hallo Kirsche,
ich bin zwar selber noch blutiger Qt-Anfänger, aber das mit dem QListView DnD hab ich Einigermaßen kapiert.
Also, du erstellst per dragObject() ein QUriDrag, etwa so:
QDragObject * DragListView::dragObject()
{
QStringList Filenames;
for( QListViewItemIterator ititems( this->firstChild()) ; ititems.current() ; ++ititems)
{
if ((*(*ititems)).isSelected())
{
Filenames += (*(*ititems)).text(0);
}
}
QUriDrag* d = new QUriDrag(this);
d->setFileNames(Filenames);
return d;
}
(Das ist von mir, wenn mehrere Filenames verwendet werden. Musst halt ein wenig anpassen).
Das ganze verändert dann auch den Cursor, und du kannst sogar noch ein Pixmap angeben, das dann "mitgezogen" wird.
Wenn du dann damit über ein anderes Widget kommst, bekommt dieses eben die Signale, wie Anda_Skoa gesagt hat, und mit deiner eigenen Klasse sagst du dann, was passiert, wenn es wirklich dieses Drop event gibt. Aber da muss ich einfach auf das Qt buch (das ebook von blanchette usw. gibts auf der trolltech seite iirc) verweisen, da ist das super erklärt, nur der Teil mit den QListViews ist da leider nicht drin.
Naja, viel Glück und Spaß (was tolles: man kann auch aus z.B. Konqueror dann in dein Programm ziehen, das erzeugt auch diese QUriDrags ;))
Hallo Sid,
danke für die Erklärungen. Ich habe sogar das Buch von Jasmin Blanchette, aber wie du gesagt hast, fehlt QListView. Ich wusste nicht, wie ich die Erklärungen dafür umsetzen sollte.
Wenn ich deinen Code richtig verstehe, leitest du QListView ab (genannt DragListView) und erstellst darin eine Funktion dragObject(), oder?
Wenn ich dann noch ein Bild angebe, sehe ich, ob sich was tut oder nicht. Daran kann ich erkennen, ob zumindest Drag funktioniert, oder? Wenn ich dann loslasse passiert vermutlich erst einmal noch nichts.
"Drop" muss ich dann für mein QWorkspace implementieren, richtig? Geht das so, oder muss ich davon auch eine Klasse ableiten? Muss ich einen Eventfilter benutzen?
Ich denke, beim DropEvent muss ich dann nur noch unterscheiden, ob schon ein Fenster geöffnet ist oder nicht. Angenommen, ich lasse mein Objekt schon los, bevor ich das geöffnete Fenster errreiche: Soll ich es dann trotzdem öffnen, oder sollte man schon genau treffen? Dann müsste ich nämlich zwei Sachen kontrollieren, nämlich ob ich den Workspace treffe (wenn das Fenster zu ist) bzw. ob ich das geöffnete Fenster treffe. Was ist sinnvoll?
Schöne Grüße,
anda_skoa
23-08-2005, 16:16
Wenn ich deinen Code richtig verstehe, leitest du QListView ab (genannt DragListView) und erstellst darin eine Funktion dragObject(), oder?
Korrekt
Wenn ich dann noch ein Bild angebe, sehe ich, ob sich was tut oder nicht.
Das Bild ist optional. man hat auch ohne Bild eine Drag Visualisierung.
Daran kann ich erkennen, ob zumindest Drag funktioniert, oder? Wenn ich dann loslasse passiert vermutlich erst einmal noch nichts.
Korrekt
"Drop" muss ich dann für mein QWorkspace implementieren, richtig? Geht das so, oder muss ich davon auch eine Klasse ableiten? Muss ich einen Eventfilter benutzen?
Sollte beides gehen.
Ableiten ist vermutlich sauberer.
Soll ich es dann trotzdem öffnen, oder sollte man schon genau treffen?
Wenn es nicht auf Grund von Vorgaben unmöglich sein soll zwei Dateien zu öffnen, würde ich ein bereits offenes Fenster nur ändern, wenn es genau getroffen wird.
Ciao,
_
Hallo Sid, hallo anda_skoa,
"Drag" funktioniert jetzt. Nur "Drop" geht noch nicht. Wenn ich den QListViewItem nach rechts ziehe, erscheint ein durchgestrichener Kreis, der vermutlich bedeutet, dass dort ein "Drop" nicht akzeptiert wird. Woran kannn das liegen? Hier ist mein Code ( ich möchte einfach eine Message ausgeben, um zu gucken, ob es klappt):
...
mdi = new QWorkspace( this, "workspace" );
mdi->setAcceptDrops( true );
setCentralWidget( mdi );
...
bool MainWindow::eventFilter( QObject *obj, QEvent *e )
{
if ( obj == mdi )
{
if ( e->type() == QEvent::Drop)
{
QMessageBox::information ( this, "Information", "DropEvent", QMessageBox::Ok , 0, 0 );
return false;
}
else
{
return false;
}
}
else
{
// pass the event on to the parent class
return QWidget::eventFilter( obj, e );
}
}
Vielen Dank,
anda_skoa
24-08-2005, 10:09
Du mußt das Event accepten, weil sonst das D&D nicht weiß, daß du die Daten wirklich transferiert haben willst.
Ciao,
_
Hallo anda_skoa,
irgendwie klappt das trotzddem nicht. Meintest du das so mit dem "accept" ?
...
if ( e->type() == QEvent::Drop)
{
QDropEvent* d = (QDropEvent*)e;
d->accept( true );
const char *str = d->format( 0 );
QString fileName( str );
QMessageBox::information ( this, "Information", fileName, QMessageBox::Ok , 0, 0 );
return false;
}
...
Ich möchte einfach nur den ersten Dateinamen ausgeben (passiert aber nicht) Später kommt stattdessen ein Funktionsaufruf.
Schöne Grüße,
anda_skoa
24-08-2005, 12:18
QMimeSource::format gibt das Format der Drag&Drop Daten an, also in diesem Fall application/x-uri-list oder so ähnlich.
Wenn man nur einen Typ erwartet macht man das normalerweise so
event->accept(QUriDrag::canDecode(event));
D.h man fragt seine Drag Klasse, ob sie mit den Daten was anfangen kann.
Vermutlich mußt du aber auch DragEnter und DragMove Event behandeln
Ciao,
_
Ich hab in meiner Klasse (leider recht groß geworden, da ich dieses zwischen den items einsetzten hab wollte aber keine kde dependencies ;)) das accept im ContentsDragMoveEvent.
Hallo anda_skoa, hallo Sid,
ich habe beides ausprobiert, aber irgendwie geht es immer noch nicht.
1.
QDropEvent* d = (QDropEvent*)event;
d->accept(QUriDrag::canDecode(d));
Dabei passiert nichts. Woher soll mein Workspace wissen, ob es die Daten akzeptieren darf oder nicht? Ich möchte beim "Drop" schließlich eine Funktion aufrufen.
2.
QEvent::DragMove funktioniert zwar, aber dann tritt das Ereignis ein, sobald ich über den Workspace fahre. Oder soll ich dort nur dafür sorgen, dass sich der Mauszeiger in ein anderes Symbol verwandelt?
Vielen Dank,
Zieh doch mal testweise dein QUriDrag dings innen konqueror. der sollte das akzeptieren.
QDropEvent* d = (QDropEvent*)event;
d->accept(QUriDrag::canDecode(d));
Da kannst du dir eigentlich die erste Zeile sparen.
2.
QEvent::DragMove funktioniert zwar, aber dann tritt das Ereignis ein, sobald ich über den Workspace fahre. Oder soll ich dort nur dafür sorgen, dass sich der Mauszeiger in ein anderes Symbol verwandelt?
Du sollst bei DragMove das d->accept() machen. Dann weiß qt, dass es da hin droppen kann und der mauszeiger ändert sich automatisch. kannst ja mal testweise alles accepten.
Später kannst du dann beim Dropevent das machen, was passieren soll.
Hallo Sid, hallo anda_skoa
vielen Dank für eure Hilfe. Es klappt jetzt! So habe ich es gemacht:
if ( event->type() == QEvent::DragMove )
{
QDragMoveEvent* d = (QDragMoveEvent*)event;
d->accept( true );
return false;
}
und
if ( event->type() == QEvent::Drop)
{
QDropEvent* d = (QDropEvent*)event;
d->accept( true );
// get name(s) of file(s)
QStringList list;
QUriDrag::decodeLocalFiles ( d, list );
QString fileName;
for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
{
QFileInfo file( *it );
fileName = file.fileName();
// Funktionsaufrufe
}
}
Schöne Grüße,
anda_skoa
25-08-2005, 09:23
Ich würde schon dazu raten, QUriDrag::canDecode zu benutzen um festzustellen, ob du das Event akzeptieren willst.
Derzeit akzeptierst du jede Art von Drag und auch den Drop und würdest bei etwas anderem als einem UriDrag dann beim Dekodieren in eine Fehler Situation geraten.
Besser gleich jeden Nicht-UriDrag ablehnen.
Ciao,
_
Hallo anda_skoa,
woher weiß mein Workspace, dass er UriDrags akzeptieren darf? Das muss ich ihm doch extra sagen, oder? Wie mache ich das? Im MoveEvent?
Schöne Grüße,
Kirstin
anda_skoa
25-08-2005, 13:19
Gleicher Code wie bisher, nur eben kein hartkodiertes "true" für die accept()
Ciao,
_
Hallo anda_skoa,
danke für den Hinweis. Ich habe es jetzt geändert. :)
Schöne Grüße,
Powered by vBulletin® Version 4.2.5 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.