[Solved] QSqlTableModel und Drag'n'Drop
-
wenn es dich nicht stört das der 220 .h's includiert von denen du geschätzt 10 brauchst ... man kann auch mit nem 7.5t LKW 10 Brötchen beim Bäcker nebenan kaufen fahren .....................
-
padreigh schrieb:
wenn es dich nicht stört das der 220 .h's includiert von denen du geschätzt 10 brauchst ... man kann auch mit nem 7.5t LKW 10 Brötchen beim Bäcker nebenan kaufen fahren .....................
Ok, fehler erkannt und geändert
QtGui Raus und dafür QDialog, QDropEvent, und QDragEnterEvent rein.Wenn du mich jetzt noch auf den richtigen weg stößt warum das erste Drag-Event leer ist bau ich dir nen Denkmal in mein Programm
EDIT: Typos
-
Sorry, hab mit DnD noch nichts gemacht ... und bin zu müd jetzt nachzusurfen, ich schau morgen mal
-
Ich danke dir wie verrückt, ich hab dir mal meinen zusammengeschusterten Quellcode auf Pastebin gepackt.
Gute Nacht!
-
So klappts (95% copy&paste from: http://doc.trolltech.com/4.6/model-view-dnd.html) ..
Änderung: Gegenüber QStringListModel erlaube ich nur MoveActions keine Copy Actions. Ich denke den eigenen MimeType sowie dekodierung/encodierung könnte man auch noch sparen wenn man als encodierung text/plain wählt ... war aber zu faul dazu
#ifndef WIDGET_H #define WIDGET_H #include <QStringListModel> #include <QMimeData> class DragDropStringListModel : public QStringListModel { Q_OBJECT public: DragDropStringListModel ( QObject * parent = 0 ) : QStringListModel(parent) {} DragDropStringListModel ( const QStringList & strings, QObject * parent = 0 ) : QStringListModel(strings, parent) {} Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } Qt::ItemFlags flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = QStringListModel::flags(index); if (index.isValid()) return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; else return Qt::ItemIsDropEnabled | defaultFlags; } QStringList mimeTypes() const { QStringList types; types << "application/vnd.text.list"; return types; } QMimeData * mimeData(const QModelIndexList &indexes) const { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); foreach (QModelIndex index, indexes) { if (index.isValid()) { QString text = data(index, Qt::DisplayRole).toString(); stream << text; } } mimeData->setData("application/vnd.text.list", encodedData); return mimeData; } bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if (action == Qt::IgnoreAction) return true; if (!data->hasFormat("application/vnd.text.list")) return false; if (column > 0) return false; int beginRow; if (row != -1) { beginRow = row; } else if (parent.isValid()) { beginRow = parent.row(); } else { beginRow = rowCount(QModelIndex()); } QByteArray encodedData = data->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList newItems; int rows = 0; while (!stream.atEnd()) { QString text; stream >> text; newItems << text; ++rows; } insertRows(beginRow, rows, QModelIndex()); foreach (QString text, newItems) { QModelIndex idx = index(beginRow, 0, QModelIndex()); setData(idx, text); beginRow++; } return true; } }; #include <QtGui/QWidget> class QTreeView; class QGridLayout; class DragDropWidget : public QWidget { Q_OBJECT public: DragDropWidget(QWidget *parent = 0); protected: private: QGridLayout * lay; QTreeView * v1; QTreeView * v2; DragDropStringListModel * m1; DragDropStringListModel * m2; }; #endif // WIDGET_H
#include "widget.h" #include <QtGui> // faul ... müde ... erkältet. lieber nur nötiges einbinden. DragDropWidget::DragDropWidget(QWidget *parent) : QWidget(parent) { lay = new QGridLayout(this); v1 = new QTreeView(this); v1->setSelectionMode(QAbstractItemView::SingleSelection); v1->setDragEnabled(true); v1->viewport()->setAcceptDrops(true); v1->setDropIndicatorShown(true); v2 = new QTreeView(this); v2->setDragEnabled(true); v2->viewport()->setAcceptDrops(true); v2->setDropIndicatorShown(true); v2->setSelectionMode(QAbstractItemView::SingleSelection); v1->setDragDropMode(QAbstractItemView::DragDrop); v2->setDragDropMode(QAbstractItemView::DragDrop); lay->addWidget(v1,0,0); lay->setColumnMinimumWidth(1,30); lay->addWidget(v2,0,2); m1 = new DragDropStringListModel(QString("1,2,3,4,5,6").split(","), this); m2 = new DragDropStringListModel(QStringList(), this); v1->setModel(m1); v2->setModel(m2); }
-
Super, funktioniert soweit mit eine paar winzigen Korrekturen die vom C&P kommen. Herzlichen Dank erstmal
Nun bleiben eigentlich nur noch kleinigkeiten (hoffe ich)
1.) Wie kann ich auf die Daten der Drop-Seite zugreifen ? Soweit ich das sehe hat ja die QStringList ja keinen Namen. Kann ich dort einfach einen festlegen ?
2.) Kann ich die Anzahl der Drops beschränken? So das die Dropseite nur X Elemtente der Drag-Seite akzeptiert ?
3.) Was sich auch bei deinem Beispiel nicht ändert, ist das auf der Drag-Seite nach dem Move leere Elemente entstehen die auch gedragt werden können, kann man das umgehen ?
-
wenn du mal genau schaust, HAT meine 2. View ein QStringListModel dran, das ist halt zu Anfang nur leer ... warscheinlich fehlt das bei dir und führt zu diesem Verhalten ... bei mir gibts keine leeren, drag-baren Elemente.
-
padreigh schrieb:
wenn du mal genau schaust, HAT meine 2. View ein QStringListModel dran, das ist halt zu Anfang nur leer ... warscheinlich fehlt das bei dir und führt zu diesem Verhalten ... bei mir gibts keine leeren, drag-baren Elemente.
Es lag daran das ich statt einem QTreeView ein QTableView hatte, nach umstellung auf QTreeView hab ich das Verhalten mit den Leeren Elementen auch nicht mehr.
Bleiben die fragen, wie komme ich an die Daten der QStringList von m2 und kann ich die größe der QStringList von m2 Beschränken das sie nur x drops Akzeptiert?
-
Eigeninitiative ?!? API ?!?
QStringList QStringListModel::stringList () const
Schau das abgeleitete QStringListModel an, verpass dem intern ein private member
int m_maxPlatz;
Initialisier den im Konstruktor auf -1. Spendier dem ganzen ne public Methodevoid setMaxPlatz(int wieviele=-1) { if (wieviele == -1 || (wieviele > 0 && wieviele > view.strinList().size())) m_maxPlatz=wieviele; }
und überprüf imdropMimeTarget(...)
ob die derzeite stringlistengröße+1 größer m_maxPlatz wird, wenn ja, returniere false ... wenn m_maxPlatz == -1 dann sparste dir die Überprüfung da dann unbegrenzt platz is ...
-
Vielen Dank erstmal, ich hab nun heftig hin und her probiert. Der Weg ist soweit klar aber mit diesem Teil
padreigh schrieb:
...0 && wieviele > view.strinList().size())) ...
hab ich meine schwierigkeiten .... Mir ist nicht so ganz klar wie ich darauf zugreifen soll, ohne dabei etwas zu benutzen, was verhindern würde das ich das ganze an andere stelle einfach wiederverwenden könnte .... kannst du mir da bitte nochmal auf die Sprünge helfen ?
-
Nach ein wenig Trial&Error bin ich nun fast da angelangt wo ich hinwollte. Welche Optionen auf der Dropseite sind, diese Auszulesen etc. funktioniert. Auch das die Dropseite nur eine Anzahl X optionen akzeptiert funktioniert. Nur hab ich nun noch 1 Problem, wenn ich die Anzahl der Maximalen Plätze auf der Dropseite erreicht habe, kann ich auch nicht mehr zurückschieben.
Mit diesem Code wird ja nachgeschaut, an welche Stelle der "Drop" eingefügt wird.
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if (action == Qt::IgnoreAction) return true; if (!data->hasFormat("application/vnd.text.list")) return false; if (column > 0) return false; int beginRow; if (row != -1) { beginRow = row; } else if (parent.isValid()) { beginRow = parent.row(); } else { beginRow = rowCount(QModelIndex()); }
Kann ich irgendwie mit einem vergleich oder ähnlichem Feststellen, auf welche Stringliste da gerade geprüft wird ? Das ist mir im moment noch ein kleines Rätsel ....
-
Dann hast du warscheinlich was anders gemacht als ich vorgeschlagen hab ... zB die Anzahl hardgecoded? Sonst wäre es einfach in der einen QStringListModelKlasse lässt du m_maxPlatz auf -1 (== unbegrenzt), in der anderen wo es beschränkt ist, beschränkst du es halt ...
ich meinte sowas:
#ifndef WIDGET_H #define WIDGET_H #include <QStringListModel> #include <QMimeData> /* alle unrelevanten Stellen entFERNT */ class DragDropStringListModel : public QStringListModel { Q_OBJECT private: int m_maxItems; /* HIIIIIIIIIIIIIER */ public: DragDropStringListModel ( QObject * parent = 0 ) : QStringListModel(parent), m_maxItems(-1) {} /* HIIIIIIIIIIIIIER */ DragDropStringListModel ( const QStringList & strings, QObject * parent = 0 ) : QStringListModel(strings, parent), m_maxItems(-1) {} /* HIIIIIIIIIIIIIER */ void setMaxItems(int nr = -1) { if (nr > 0 && nr < stringList().size()) m_maxItems = nr; else m_maxItems=-1; } /* HIIIIIIIIIIIIIER */ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if (action == Qt::IgnoreAction) return true; if (!data->hasFormat("application/vnd.text.list")) return false; if (column > 0) return false; if (m_maxItems == stringList().size()) /* HIIIIIIIIIIIIIER */ return false; // usw. } };
sollte tun ...
-
Naja, etwas. Also erstmal hab ich ne Methode zum setzen der m_maxPlatz geschrieben. Dann prüf ich in der
Qt::DropActions supportedDropActions() const
Ob Maxplatz -1 ist, oder ne Hilfsvariable z < Maxplatz. Wenn das gegeben ist, dann ActionMove, wenn nicht ActionIgnore.
Nur wenn ActionMove ist, wird ja dann diebool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
durchlaufen, dort erhöhe ich die hilfsvariable z um 1.
Und genau da ist das Problem ... denn sowohl von Rechts nach Links, als auch von Links nach rechts, wird ja z um 1 größer. Helfen würde mir nun, wenn ich die Richtung unterscheiden könnte, und danach z erhöhe oder verringere. Aber hier komm ich nicht weiter ....
Nen wirklich anderen Lösungsansatz hab ich irgendwie nicht gefunden, weil ich ja kein Objekt auf meine Vas-Klasse erstellen will, womit ich die größe der Stringliste in m1 bzw m2. auslesen könnte. Denn ich würde gern die hierfür erstelle model.h gern an deren Stelle im Programm wieder verwenden.
-
Hilfsvariable z HÄH? ... schau dir meinen CodePost wo
/* HIIIIIIIIIIIIIER */
steht ...Bei der Instanziierung
DragDropStringListModel m1; DragDropStringListModel m2; QTreeView v1; QTreeView v2; v1.setModel(m1); v2.setModel(m2); m2.setMaxItems(10);
Feddich ist ... dann prüft das eine model beim dropppen nicht ( da maxAnzahl auf -1) das andere prüft (da maxAnahl>-1). Das DragDropStringListModel erbt von QStringListModel und wird doch wohl noch seine eigene stringList().size() abfragen dürfen!?! Ich hoffe du trennst das auch wieder in .cpp und .h auf ... ich poste das hier nur so reinimplementiert weil das fürs Forum kürzer ist ... in die .h nur die Bekanntmachung der Methoden, in die .cpp die Implementierung !!
-
nalamar schrieb:
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
Wenn ich das richtig deute sagt dir
action
was passieren soll ... ist das nicht möglich returnierst du false, sonst machst du es und returnierst true ... du kannst natürlich die action beliebig umsetzen, das hat aber keine Konsequenz da die als Kopie hier reinkommt und all deine Änderungen am Ende der Methode null und void sind ...
-
Sorry, ich hab dein Edit-Code-Beispiel erst jetzt gesehen, da hatte ich schon geantwortet. Ja, zu 90% sah mein Code auch so aus.
Nur das hatte ich nicht.if (m_maxItems == size()) /* HIIIIIIIIIIIIIER */ return false;
Dort hatte ich eben ein z++; und hab eben in den supportedDropActions geschaut ob z > m_maxPlatz wird.
Und das size() meint der Kompiler ist nicht deklariert in dem Scope. Mal ganz abgesehen davon das ich so ziemlich jede Variante durchversucht haben mit parent und QModelIndex an irgend ne verwertbare Größe zu kommen und was weiß ich nicht alles, ich komme eben nun mal nicht an die Size der Stringliste .... aber ich tu mein bestes das noch rauszufinden .....
EDIT sagt: Ok ich sehe du hast dein Posting nochmal abgeändert, dann vergiss erstmal was ich geschrieben habe ... ich setze erstmal um was ich nun daraus an erkenntniss gewonnenhabe, sieht grad gut aus
-
Sooo .... nach 3 Bissen in die Tischkante funktioniert nun alles ....
Erstmal hatte ich das Problem das m_maxPlatz irgendwie nicht größer als -1 wurde .... bis mir dann auffiel das ich aus deinem Codebeispiel von Seite 1 noch folgendes hatte
m1 = new DragDropStringListModel(QString("1,2,3,4,5,6").split(","), this); m2 = new DragDropStringListModel(QStringList(), this);
Nach 5 mal durchlesen und verzweifeln das abgeändert .... und fast am Ziel gewesen. Dann blieb folgendess Problem - wenn ich die Überprüfung auf size>m_maxPlatz wirklich in die
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
Funktion packe, und die size+1>maxPlatz wird, ist es egal ob du false oder true returnierst, das DragItem verschwindet im Nichts. Also Back zu meiner Ursprünglichen Idee und das ganze nun so aufgebaut.
Qt::DropActions supportedDropActions() const { if (m_maxPlatz == -1 || stringList().size()+1 <= m_maxPlatz) { return Qt::MoveAction; } else { return Qt::IgnoreAction; } }
Und es funktioniert genau so wie ich mir das gewünscht habe. Padreigh, ich danke für deine Engelsgeduld.
Ich wünsche dir eine Gute Nacht !
EDIT: Mist, ich korrigiere meine Aussage. Wenn MaxPlatz erreicht wird funktioniert auch das zurückdraggen nicht mehr *grübel*
EDIT2: Ok, sobald das Draggen beginnt wird das erstmal mal supportedActions aufgerufen, da das Item dabei aber noch auf dem Focus der Liste ist, die Beschränkt ist, kommt als supportedaction "IgnoreAction" und das zurückdraggen funktioniert nicht. Also muss ich eine 3. Stelle finden, wo die Abfrage auf Beschränkung sinn macht.
-
Die Api hilft dir weiter ...
Qt::DropActions QAbstractItemModel::supportedDragActions () const
: Returns the actions supported by the data in this model. The default implementation returns supportedDropActions() unless specific values have been set with setSupportedDragActions().Qt::DropActions QAbstractItemModel::supportedDropActions () const [virtual]: Returns the drop actions supported by this model. The default implementation returns Qt::CopyAction. Reimplement this function if you wish to support additional actions. You must also reimplement the dropMimeData() function to handle the additional operations.
Knobeln ist beim Proggen der halbe Spass, sorry das ich ihn dir klaue
-
Läuft nun rund wie ein Buslenker .... danke sehr .....
Meine erste Idee war ja die dropMimedata umzuschreiben, das wenn size>m_maxplatz das gedragtte item einfach wieder bei der source hinten angefügt wird ... das es natürlich sooo einfach geht ..... sehr gut, nun kann ich das Kapitel endlich komplett abschließen
*verneig*
Der Nala
-
Zumindest kenn ich mich nu mit DnD auch ein wenig besser aus ... pack doch noch ein [solved] an den Thread dran ...