QT: MoveAction bei QTreeView
-
Also, zum einen kannst du in ein QVariant alles reinstecken, was du willst. Du musst lediglich irgendwo (am besten im Header nach der Klassendeklaration) ein
Q_DECLARE_METATYPE(MyClass);
haben.
Wegen den access violations... Dass du im Assemblercode landest ist kein Problem, du kannst ja im Callstack einbisschen hochgehen und schauen, wo du noch Infos bekommst, dann kannst du sicher die Fehlerursache eingrenzen.
Rufst du resetModel auf, nachdem du was eingefügt/gelöscht hast?
-
Erstmal vielen Dank, auch für den Hinweis für QVariant
Wenn ich die Aufrufkette hochwandere, lande ich leider trotzdem nur an Stellen, die ich nicht einschätzen kann. Jedoch habe ich herausgefunden, dass man QModelIndex nicht einfach als Klassenattribut halten darf. Das hatte ich temporär nämlich zum Speichern der aktuellen Position genutzt. Aus irgendeinem Grund verursacht das nach Destrukturaufruf einen Dump... habe nicht wenig auf QT geflucht, weil ich das nicht verstehe.
resetModel rufe ich nicht auf, jedoch ist ja selbst die Einfügeoperation selbst schon fehlgeschlagen und dumpt wegen Access Violation, d.h. er käme ohnehin nicht in die Zeile danach. Es ist halt so seltsam, weil ich z.B. ohne Probleme mit derselben Methode etwas einfügen kann, wenn ich es in dropMimeData schiebe. Derselbe Code dumpt jedoch, wenn ich aus einem Pushbutton heraus den Aufruf mache.
Edit: Wenn ich jetzt über ein Signal etwas hinzufüge, also beim Klick auf Button ein Signal losschieße, dass im Model einen Slot hat, der einfügt, was ich will, dann dumpt er nicht?! Da war meine Intuition richtig, aber wieso ist so was so?
Edit2: Okay, also wenn ich einfach etwas ins Modell einfüge und eben keine Signale emittiere, dann dumpt er auch nicht. Und auch im Beispiel von QT werden ja keine Signale gesendet. Doch wie erreiche ich den Refresh dann? Mache ich das über resetModel? (bzw. habe nur reset gefunden) Aber dann klappt er es ja auch wieder zu, ich hätte es schon gerne so, dass er alles so lässt, wie es ist.
-
Wenn es crasht, dann machst du sicher was falsch. Das muss dir klar sein und den Fehler solltest du finden und nicht versuchen, ihn zu umgehen.
Ein Model hat mehrere Signale, die dem View mitteilen, dass sich was geändert hat. Die kann man in der Ableitung nicht direkt auslösen, sondern muss protected Methoden aufrufen, sowas wie beginInsertRows, endInsertRows usw.
-
Wenn es crasht, dann machst du sicher was falsch. Das muss dir klar sein und den Fehler solltest du finden und nicht versuchen, ihn zu umgehen.
Puh, du scheinst wirklich so überhaupt nichts von mir zu halten, wenn Du so was schreibst. Ich muss hier einen extrem schlechten Eindruck hinterlassen.
Also der Dump lag daran, dass ich QModelIndex in einem Dialog als Attribut hatte. Nach dem Löschen (ceteris paribus) dumpt er nicht mehr... außer, wenn ich eben Signale abfeuern möchte.
Na ja, ich will eben dem Tree/Model sagen, dass sich am Modell etwas geändert hat. Es wäre in meinen Augen nur sinnvoll das über ein Signal zu tun. Eigentlich dachte ich, der Vorteil am Model ist, dass man etwas an den Daten ändern kann und damit automatisch auch der View aktualisiert wird und ich eben nicht ständig darauf achten muss, dass ich an jeder Stelle zig Methoden aufrufe... aber okay.
begin/endInsertRows führen ebenfalls zu Access Violation, was auch klar ist, da die ja ihrerseits Signale aussenden. Ich neige so langsam dazu einfach alles in Slots des Modells auszulagern und über Signal/Slot-Mechanismus die Aufrufe zu tätigen. Wenn ich etwas einfüge und kein Signal sende, dumpt er ja auch nicht mehr und alles klappt, bis auf das Aktualisieren. Reset klappt, aber dadurch wird eben der Baum wieder collapsed, was je nach Tiefe für den Benutzer sehr ärgerlich ist.
-
Eisflamme schrieb:
Puh, du scheinst wirklich so überhaupt nichts von mir zu halten, wenn Du so was schreibst. Ich muss hier einen extrem schlechten Eindruck hinterlassen.
Durchaus nicht. Aber was ich geschrieben habe, mein ich auch so und deine letzte Antwort bestätigt den Eindruck auch
Also, nicht den "schlechten Eindruck" von dir, sondern den Eindruck, dass du irgendwo einen Fehler hast.
Das ist genauso gedacht. Wenn du Zeilen in ein Model einfügst, dann rufst du in der Ableitung beginInsertRows und endInsertRows auf. Das löst entsprechende Signale aus. Das View connected Slots auf diese Signale beim Setzen des Models und aktualisiert die Anzeige, wenn das nötig ist. Wenn das nicht funktioniert, ist definitiv etwas falsch. Das muss so funktionieren.
-
Okay, dann bin ich ja beruhigt... jedoch...
Das Problem war, dass ich im QDialog das TreeModel mit new erstellt hab. Dann habe ich tree->setModel(model); aufgerufen und danach ist model genullt... d.h. ich habe über einen nullptr die Methode aufgerufen. :headbang: Wieso das Element nach Aktualisieren dann trotzdem eingefügt war, weiß niemand. Na ja, undefiniertes Verhalten halt...
Manchmal ist QT so unberechenbar, wieso invalidiert der denn nach setModel einfach meinen Zeiger.
(Edit: moment Mal, das ergibt so keinen Sinn)
Vielen Dank nochmal!!
Mit
static_cast<...*>(tree->model())->InsertTest(idx);
funktioniert alles. Und dafür saß ich jetzt Stunden dran. Ich lass mich jetzt mit ner Schrottflinte vom Balkon runter an einen Galgen schießen, in dem ich dann einen Schierlingsbecher trinke, während die Dynamitladung zündet. So ein Scheißfehler...Edit:
Ich verstehe das immer noch nicht. Ich habe mein model jetzt Mal als konstanten Zeiger angelegt, sodass den niemand mehr verändern kann. setModel ändert den Zeiger auch nicht, aber wenn ich in die Slot-Methode komme, die vom Pushbutton-Signal aufgerufen wird, dann zeigt mir 1. der Debugger nicht mehr den Wert des Model-Zeigers an (muss ich also in einen anderen Pointer schieben, um zu debuggen) und dann ist dieser andere Zeiger eben nullptr?! Und das obwohl der this-Zeiger die gleiche Adresse hat und der Zeiger konstant ist, also nicht geändert werden kann. Was geschieht hier??Edit X:
Übrigens klappen layoutAboutToBeChanged() und layoutChanged() jetzt auch. Ich denke jedoch, das ist auch in Ordnung, da ich schon einige Beispiele sah, die nicht über beginInsertRows() solche Einfügungen gemacht haben. Was wäre überhaupt der Vorteil davon?Edit Y:
Okay, ich habe bereits einen Bug gefunden, weil ich es nicht brav mit beginInsertRows gemacht habe, dann mache ich das jetzt Mal lieber damit *duck und wegrenn*
-
Wie ist jetzt der Status nach den vielen Edits?
setModel kann deinen Zeiger nicht ändern. Er kann aber das Objekt löschen (macht er aber sicher nicht). Du könntest einen Breakpoint in den Destruktor von deinem Model setzen und schauen, ob das gelöscht wird. Aber ich schätz mal, du hast einfach irgendwo eine Kleinigkeit übersehen.
-
Also es funktioniert jetzt alles, weil ich nicht über diesen Zeiger zugreife, sondern mir einfach vom Tree das Model über ->model() hole, caste und dann damit arbeite. Diverse Bugs konnte ich dann beseitigen, indem ich jetzt nirgendwo mehr selbst layoutChanged() emitte, sondern das über beginInsertRows() und Konsorten nutze. Die Bugs sind damit weg. Verwirrt hatte mich halt, dass die Doku sagt
If the structure of the underlying data changes, the model can emit layoutChanged() to indicate to any attached views that they should redisplay any items shown, taking the new structure into account.
Aber gut, jetzt läuft es.
Gelöscht wird mein Model wohl nicht, aber trotzdem hat das Zeigerattribut nachher keinen durch Debugger identifizierbaren Wert mehr, obwohl this sich nicht ändert und der Zeiger eben konstant ist. Drum versteh ich absolut nicht, wie das sein kann... ist jetzt halt auch egal, da es wie gesagt, funktioniert, seltsam ist es dennoch...
-
Wird "this" vielleicht gelöscht? Sich von der View das Model zu holen ist an sich auch nicht verkehrt, nur das casten nicht so schön. Musst du das überhaupt machen? Wenn du aus dem Model immer noch keine Signale auslösen kannst, würde es immer noch auf einen Fehler hindeuten.
-
Signale kann ich aussenden, aber ich habe jetzt halt eigene Methoden im Model geschrieben, bei denen man nur Index und neues Objekt überhaupt und darüber automatisch einfügen kann. Das Interface vom Model hat ja nicht wirklich eine Methode, die angenehm fürs Einfügen ist. (insertRow wäre okay, wenn ich inzwischen den Q-Befehl gemacht hätte, womit setData auch eine passende QVariant erhalten könnte, aber das habe ich noch nicht gemacht; trotzdem ist das alles länger als mein Einzeiler, den ich dank meiner Methoden machen kann)