2016-03-28 13 views
1

Ich versuche, Drag & Drop-Elemente (plain/Text) von einem QListView zum anderen zu implementieren. Das Ziehen beginnt gut (ich kann sogar Elemente in andere Anwendungen verschieben, die Texttropfen akzeptieren), aber meine zweite QListView akzeptiert aus irgendeinem Grund keine Tropfen. Hier ist wie die Listenansicht konfiguriert:QListView externen Tropfen funktioniert nicht

ui->lessonsListView->setAcceptDrops(true); 
ui->lessonsListView->setDropIndicatorShown(true); 
ui->lessonsListView->setDragDropMode(QAbstractItemView::DropOnly); 
ui->lessonsListView->setDragDropOverwriteMode(true); 

Das Proxy-Modell für diese Listview implementiert die nächsten Methoden:

Qt::ItemFlags LessonsProxyModel::flags(const QModelIndex &index) const 
{ 
    qDebug() << __FUNCTION__; 
    return Qt::ItemIsDropEnabled | QSortFilterProxyModel::flags(index); 
} 

Qt::DropActions LessonsProxyModel::supportedDropActions() const 
{ 
    qDebug() << __FUNCTION__; 
    return Qt::MoveAction; 
} 

bool LessonsProxyModel::canDropMimeData(const QMimeData *data, 
    Qt::DropAction action, int row, int column, const QModelIndex &parent) 
{ 
    qDebug() << __FUNCTION__; 
    Q_UNUSED(action); 
    Q_UNUSED(row); 
    Q_UNUSED(column); 

    if (!data->hasFormat("text/plain") || !parent.isValid()) 
     return false; 

    return true; 
} 

bool LessonsProxyModel::dropMimeData(const QMimeData *data, 
    Qt::DropAction action, int row, int column, const QModelIndex &parent) 
{ 
    qDebug() << __FUNCTION__; 
    if (!canDropMimeData(data, action, row, column, parent)) 
     return false; 

    emit dataDropped(data, parent); 

    return true; 
} 

den Anwendungs ​​Ausgang Ich sehe, dass nur supportedDropActions() und flags() genannt werden. Weder canDropMimeData() noch dropMimeData() jemals genannt. Was mache ich falsch? Alle Hinweise werden geschätzt.

Vielen Dank!

EDITED:

Nur für den Fall: unten ist Quellcode für Listview und das Modell an dieser Stelle ziehen initiiert wird: Listview-Setup:

ui->abonsListView->setDragEnabled(true); 

proxyModel Code:

Qt::ItemFlags AbonsProxyModel::flags(const QModelIndex &index) const 
{ 
    return Qt::ItemIsDragEnabled | QSortFilterProxyModel::flags(index); 
} 

Qt::DropActions AbonsProxyModel::supportedDragActions() const 
{ 
    qDebug() << __FUNCTION__; 
    return Qt::MoveAction; 
} 

QStringList AbonsProxyModel::mimeTypes() const 
{ 
    qDebug() << __FUNCTION__; 
    QStringList types; 
    types << "text/plain"; 
    return types; 
} 

QMimeData *AbonsProxyModel::mimeData(const QModelIndexList &indexes) const 
{ 
    qDebug() << __FUNCTION__; 
    QMimeData *mimeData = new QMimeData(); 

    foreach (const QModelIndex &index, indexes) 
     if (index.isValid()) 
     { 
      mimeData->setText(data(index, AbonsModel::Id).toString()); 
      qDebug() << __FUNCTION__; 
      return mimeData; 
     } 

    return mimeData; 
} 
+0

Ich glaube, Sie müssen 'dragEnterEvent',' dragMoveEvent' und 'dropEvent' der' QListView'-Unterklasse außer Kraft setzen. Sehen Sie sich die [Dokumentation] (http://doc.qt.io/qt-5/dnd.html) und [examples] (http://doc.qt.io/qt-5/examples-draganddrop) an. html) – Marcus

+0

Danke! Ich werde es versuchen. Aber die obige Dokumentation besagt: 'Dieses Dokument beschreibt den grundlegenden Drag & Drop-Mechanismus und umreißt den Ansatz, der verwendet wird, um es in benutzerdefinierten Steuerelementen zu aktivieren. Und ich folgte nur den Anweisungen unter dem Link" Verwenden von Drag & Drop mit Elementansichten ". Ziehen Sie auch die Arbeit perfekt für eine andere Listenansicht ohne Unterklassen: Objektansichten haben bereits Unterstützung für Drag & Drop. –

+0

Ja ist der Widerstand perfekt implementiert. Der Drop funktioniert jedoch nicht wie erwartet. Ich habe versucht, ein einfaches Drag-and-Drop-Experiment mit einem 'QListView' verbunden mit' QFileSystemModel' und einem Datei-Browser (Delfin) durchzuführen. Das Ziehen von 'QListView' nach Delfin funktioniert wunderbar, aber umgekehrt ist das nicht akzeptabel. Also glaube ich, dass Sie 'dragEnterEvent',' dragMoveEvent' und 'dropEvent' für das Widget einrichten müssen, in dem Sie den Drop durchführen wollen. – Marcus

Antwort

1

nennen kann ich endlich eine gefunden habe Antworten! Als ich anfing, diesen Code zu schreiben, kopierte ich einige Stücke aus Qt-Dokumenten Using Drag and Drop with Item Views und in diesem Artikel verpassten sie gerade const Spezifizierer für Reimplementation von canDropMimeData(). Daher wurde meine Version canDropMimeData() nicht virtuell und QListView hat nur die Methode aus der Basisklasse QAbstractProxyModel aufgerufen. Ich habe const hinzugefügt - und alles funktioniert wie ein Charme ohne irgendwelche Unterklassen.

0

Ich habe nicht viel Erfahrung mit Proxy-Modellen. Wenn ich durch die Dokumente gehe, denke ich, dass ich eine ungefähre Vorstellung davon habe, was diese beiden Funktionen sind. Diese Funktionen werden nicht automatisch aufgerufen. Sie müssen sie aus Ihrer Sicht "anrufen".

Zuerst, ob Sie die richtigen Daten haben, ist die Arbeit des Modells. Das sind also zwei Komfortfunktionen im Modell, um Ihre Arbeit zu erleichtern. Dies sind modellspezifische Funktionen und keine generischen Funktionen und daher niemals für ein abstraktes Modell definiert.

Betrachten Sie dieses Szenario. Von irgendwo wird ein QMimeData Objekt in Ihre Ansicht fallengelassen. Woher weißt du, ob diese Daten vom richtigen Typ sind? Wessen Arbeit ist es zu entscheiden, ob die Daten vom richtigen Typ sind?

In der Rahmen, View arbeitet nur Malerei. Es liegt an der Model zu entscheiden, Dinge wie die Daten zu verarbeiten, was zu zeigen, was ist akzeptabel und was nicht. Wenn also ein Stück Daten auf die View fallen gelassen wird, müssen Sie es an die Model senden, um zu überprüfen, ob die abgelegten Daten die Anforderung Model erfüllen. Der Haken für diese Arbeit ist bool Model::canDropMimeData(...).

Wenn es akzeptabel ist, dann muss die Verarbeitung der Daten auch von der Model selbst durchgeführt werden. Auch hier müssen Sie die Daten an die Model senden. Der Haken dafür ist bool Model::dropMimeData(...).

Woher wissen Sie, ob die Daten erfolgreich verarbeitet wurden? Überprüfen Sie den Rückgabewert! Wenn die Daten erfolgreich verarbeitet wurden, müssen Sie wahrscheinlich Ihre View aktualisieren.

So zusätzlich zu dem Code, den Sie oben haben, können Sie MUST überschreiben die dragEnterEvent, dragMoveEvent und dropEvent des Empfangs View, so dass Sie canDropMimeData(...) und dropMimeData(...)

/* You need to allow the drag to enter the widget/view. */ 
/* This is a must. */ 
void TargetView::dragEnterEvent(QDragEnterEvent *deEvent) { 

    deEvent->acceptProposedAction(); 
}; 

/* This is optional. Use this to check if the data can be */ 
/* dropped at the current mouse position. Example: In a */ 
/* FileSystem View, it makes no sense to drop a bunch of */ 
/* files on top of a file, but makes sense it you drop it */ 
/* in an empty space or on a folder */ 
void TargetView::dragMoveEvent(QDragMoveEvent *dmEvent) { 
    /* You can do something like this */ 
    if (indexAt(dmEvent->pos()).isValid()) { 
     /* You cannot drop it on an existing index */ 
     /* If you ignore it, the cursor changes to */ 
     /* 'don't drop' image */ 
     dmEvent->ignore(); 
    } 

    else { 
     /* Empty space. Tell the user to feel free */ 
     /* to perform the drop. We accept the event */ 
     /* Cursor shows the drag+drop icon */ 
     dmEvent->accept(); 
    } 
}; 

void TargetView::dropEvent(QDropEvent *dpEvent) { 
    /* Here is where you call canDropMimeData and dropMimeData */ 
    QMimeData *mData = dpEvent->mimeData(); 
    if (model->canDropMimeData(mData, ..., ..., ..., ...)) { 
     /* Add the data to the model */ 
     bool updated = model->dropMimeData(mData, ..., ..., ..., ...); 
     if (updated) { 
      /* Intimate the view to update itself */ 
      update(); 
     } 
    } 
};