QTreeView: Geändertes Item auslesen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Hallo!

Ich muss nun wohl doch mal eine Frage stellen, da ich einfach den Wald vor lauter Bäumen nicht mehr sehe und einfach nicht weiter komme.

Ich arbeite schon etwas länger mit Python (unter Linux mit Gnome), habe Qt aber erst vor kurzem für mich entdeckt - und lieben gelernt. ;-)

Mein Problem ist nun Folgendes:

Ich habe eine MySQL-Tabelle, aus der zwei Spalten in einem Tree angezeigt werden sollen. (Nein, das ist noch nicht das Problem.)

Also, die Tabelle sieht so aus:

| id | item | desc | sortorder |

In "item" stehen die Aufgaben, in "desc" die zugehörigen Beschreibungen. "id" ist der automatisch gesetzte Schlüssel und "sortorder" ist im Moment noch nicht wichtig, soll später mal die Aufgaben sortieren.

Das Ganze wird eine ToDo-Liste, die von mehreren Leuten übers Internet genutzt und aktualisiert wird.

Die Darstellung sieht dann so aus:

Bild

Die Zeilen einer Beschreibung sind in der Datenbank durch Zeilenumbruch getrennt und werden dann im Programm gesplittet. Unter der Beschreibung ist dann noch ein leeres Item, das nicht aus der Datenbank kommt, um einen neuen Eintrag vornehmen zu können. Und ganz unten noch ein von der Datenbank unabhängiges Item für eine neue Aufgabe.

So weit klappt das alles schon. Der Screenshot ist brav mit Einträgen aus der Datenbank gefüllt.

Nun das Problem:

Der User soll per Doppelklick die Einträge ändern können. Geht ja. Dann sollen aber die geänderten Einträge in der Datenbank aktualisiert, bzw. neue Einträge eingefügt werden.

Das Signal, dass überhaupt etwas geändert wurde, funktioniert.

Nur möchte ich auch wissen, WAS geändert wurde, um das an die Datenbank weiter reichen zu können.

Die Frage ist also: Wie kriege ich das geänderte Item und seinen neuen Wert heraus?

Es tut mir Leid, wenn das eine selten dämliche Frage ist. Ich sehe nur, wie gesagt, den Wald vor lauter Bäumen nicht, lese über QTreeView, QTreeWidget, QAbstractItemView und so weiter. Aber ich krieg es einfach nicht zusammen. Ich suche eigentlich nach einem Beispiel-Code, der mir zeigt, wie das geht, aber ich finde einfach keinen. Vielleicht bin ich auch gerade einfach nur zu doof zum Suchen, denn das Problem muss doch bestimmt schon mal jemand gehabt haben. Oder es ist so einfach, dass sich einfach niemand die Frage stellt. Ich weiß es nicht. Ich bin auch einfach so zugeflutet mit zusammenhanglosen Informationen aus der Dokumentation oder unterschiedlichen Codes, dass ich einfach nichts mehr sortiert kriege. Ich glaube, es wird bestimmt was mit QAbstactItemView zu tun haben, aber ich weiß nicht mal, wie ich das mit den Items verknüpfen soll oder wie es dann weiter geht. Oder es will mir grad einfach nicht in den Schädel. Also falls die Frage zu dämlich ist, entschuldigt bitte, aber ich komm da grad echt nicht mit klar, obwohl ich mir wirklich Mühe gebe.

Hier mal der relevante Ausschnitt aus meinem Code:

Code: Alles auswählen

	def itemTable(self):
		ItemWidget = QtGui.QTreeView()
		
		ItemModel = QtGui.QStandardItemModel()
		
		result = db.query("SELECT * FROM items ORDER BY sortorder")
		for i in xrange(result.num_rows()):
			row = result.fetch_row()
			Id, Item, ItemDesc, ItemOrder= row[0]
			
			TreeItem = QtGui.QStandardItem(Item)
			ItemModel.appendRow(TreeItem)
			
			ItemDesc = ItemDesc.split('\r\n')
			
			for desc in ItemDesc:
				TreeItemDesc = QtGui.QStandardItem(desc)
				TreeItem.appendRow(TreeItemDesc)
				TreeItem.emitDataChanged()
			
			TreeItemDesc = QtGui.QStandardItem('')
			TreeItem.appendRow(TreeItemDesc)
		
		TreeItem = QtGui.QStandardItem('<Neue Aufgabe>')
		
		ItemModel.appendRow(TreeItem)
		#self.connect(ItemModel, QtCore.SIGNAL('itemChanged()'), self.updateItemDesc)
		#self.connect(ItemWidget, QtCore.SIGNAL('doubleClicked(const QModelIndex &)'), self.updateItemDesc)
		self.connect(ItemWidget, QtCore.SIGNAL('doubleClicked(const QModelIndex &)'), self.test1) 
		self.connect(ItemModel, QtCore.SIGNAL('itemChanged(QStandardItem *)'), self.test2)

		
		#TreeItemDesc = QtGui.QStandardItem('<Neue Beschreibung>')
		#TreeItem.appendRow(TreeItemDesc)
		
		ItemModel.setHorizontalHeaderLabels([self.tr(u'Aufgaben')])
		
		ItemWidget.setModel(ItemModel)
		
		
		self.ItemArea = ItemWidget
	
	def test1(self):
		print 'Doppelklick'
	
	def test2(self):
		print 'Geändert'

Das Signal mit dem Doppelklick steht da nur zu Testzwecken. Das und das itemChanged-Signal funktionieren.

Falls ihr euch fragt, warum ich denn die Items nicht im self hab oder in einer Liste, ich hab da schon dran gedacht. Aber ich wollte jetzt erst mal gucken, wie das überhaupt geht mit der Wertübergabe, bevor ich vorschnell was mit einer ggf. unnützen Liste oder mit self mache (dachte, das würde sich dann bestimmt ergeben). Und lasst euch nicht von den Worten "itemTable" und "ItemWidget" irritieren. Ich hab schon mehrere Sachen probiert, bevor ich mich für den Tree entschieden hab und hatte da auch zuerst ein QTreeWidget stehen gehabt.

Es wäre schön, wenn mir jemand durch ein bisschen Code oder einen vielsagenden Link mal ein bisschen eine Richtung zeigen könnte. Oder einfach einen Tipp, wonach ich mal suchen sollte.

P.S.: Tut mir Leid, wenn mein Beitrag wirr oder unverständlich sein sollte oder wichtige Informationen fehlen. Ich reiche da gerne was nach. Ich bin nur gerade so geflutet, dass ich froh bin, wenn ich mein Problem hier halbwegs klar herausgearbeitet kriege. Ich liefere auf Wunsch auch noch zum Ausprobieren einen benutzbaren Beispiel-Code, der sich die Daten nicht aus der Datenbank fischt. Ansonsten gibt es jetzt erst mal wenigstens einen Screenshot.

P.P.S.: Wie gesagt, ich nutze Gnome. Von daher wäre es toll, wenn es eine Lösung gäbe, die auch ohne KDE-Bibliothen und sowas auskommt.
deets

Es ist ja schon ein Weilchen her bei mir mit Qt - aber wenn du schon das item-changed Signal bekommst, wo ist dann dein Problem? Das Signal uebergibt doch das geaenderte Item. Du hast in deiner test2-Funktion dafuer keinen Parameter (was mich etwas wundert, dass Qt da nicht spuckt, aber sei's drum), aber da bekommst du doch genau das geaenderte Item mit?

Was natuerlich noch fehlt ist die Assoziation von QStandardItem mit der ID. Naiv wuerde ich da einfach ein

TreeItem.item_id = Id

machen, und dann weisst du im signal ja, wen's getroffen hat.

Deine Benennungen sind uebrigens nicht PEP-8-konform, aber das nur am Rande. Und du solltest die Spalten in dem SELECT dezidiert auffuehren, sonst kannst du bei Schema-Aenderungen boese Probleme bekommen.
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Wow! Danke!!! Genau das war's!

Jetzt konnte ich dann auch mit einem Code-Beispiel was anfangen, das mir vorher einfach nichts sagen wollte. Und nach ein bisschen Rumprobieren mit dir() hab ich dann jetzt das, was ich haben wollte.

Vielen, vielen Dank!

Und auch vielen Dank für deine rasend schnelle Antwort! :D

Edit: Danke auch für die weiteren Tipps! Die werde ich mir auch zu Herzen nehmen. ;-)

Noch'n Edit: Falls jemand genau denselben Denkfehler macht wie ich und nicht weiß, dass da schon was übergeben wird, hier meine neue test2-Funktion:

Code: Alles auswählen

	def test2(self, item):
		print item.item_id, item.text()
Als item_id kann man da ja setzen, was man will, von daher dürfte es kein Problem sein, auch die Beschreibungen und die neuen Einträge zu indizieren.
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Hallo!

Ich hab dazu leider schon wieder eine (etwas andere) Frage, weil ich es einfach nicht gebacken kriege.

Nachdem das letzte Problem ja nun gelöst ist, möchte ich die Items nun per Drag&Drop verschieben und dementsprechend auch in der Datenbank ihre Reihenfolge ändern.

Das Verschieben klappt, nur bekomme ich leider keinen Wert, weil irgendwie kein Event ausgelöst wird.

Code: Alles auswählen

    def mktree(self):
        item_model = QtGui.QStandardItemModel()
        item_model.setHorizontalHeaderLabels([self.tr(u'ToDo-Liste')])

        items = {}

        result = db.query("SELECT `id`, `item`, `desc`, `sortorder` FROM items ORDER BY sortorder, id")
        for i in xrange(result.num_rows()):
            row = result.fetch_row()
            _id, _item, _item_desc, _item_order = row[0]

            items[_id] = QtGui.QStandardItem(_item)
            items[_id].item_id = _id
            items[_id].setDragEnabled(True)
            items[_id].setDropEnabled(False)  # Nur zu Testzwecken, damit ich das besser sehe und die Items nicht einfach als Children "verschwinden".
            item_model.appendRow(items[_id])

            if _item_desc:
                item_desc = _item_desc.split('\n')

                i = 0
                for desc in item_desc:
                    i += 1
                    desc = QtGui.QStandardItem(desc)
                    desc.item_id = float("%d.%d" % (_id, i))
                    desc.setDropEnabled(False)
                    items[_id].appendRow(desc)

            desc = QtGui.QStandardItem('')
            desc.item_id = float("%d.%d" % (_id, i+1))
            items[_id].appendRow(desc)

        new_item = QtGui.QStandardItem('<Neue Aufgabe>')
        new_item.item_id = 0
        item_model.appendRow(new_item)

        self.connect(item_model, QtCore.SIGNAL('itemChanged(QStandardItem *)'), self.update)  # Schickt Daten an die Datenbank. Funzt.

        tree = QtGui.QTreeView()
        #tree.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        tree.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        #tree.setDefaultDropAction(QtCore.SLOT(sys.exit()))
        #tree.setDropIndicatorShown(False)
        tree.setAcceptDrops(True)
        tree.setModel(item_model)


        for index in self.expanded_items:
            tree.setExpanded(item_model.index(index[0], index[1], index[2]), True)

        self.connect(tree, QtCore.SIGNAL('expanded(const QModelIndex&)'), self.item_expanded)  # Speichert den Zustand der Items, weil der
        self.connect(tree, QtCore.SIGNAL('collapsed(const QModelIndex&)'), self.item_collapsed)  # Tree nach dem Datenbank-Update neu geladen wird. Funzt.
        #self.connect(tree, QtCore.SIGNAL('dropEvent(QDropEvent)'), self.startDrag)
        #self.connect(tree, QtCore.SIGNAL("dragEnterEvent(QDragEnterEvent)"), self.dragReceived)
        #self.connect(tree, QtCore.SIGNAL("dropEvent(QDropEvent)"), self.dropReceived)


        self.todo_tree = tree

    def event(self, event):
        event.accept()
        print event  # Geht durch.

    def dragReceived(self, e):
        #e.accept()
        print "Connect Dragged"

    def dropReceived(self, e):
        print "Connect Dropped"


    def startDrag(self, event):
        print 'drag'

    def dragEnterEvent(self, event):
        event.accept()
        print 'de'
    def dropEvent(self):
        pass

    def dragMoveEvent(self, event):
        event.accept()
        print 'dm'

    def mouseMoveEvent(self, event):

        print 'mouse'

        mimeData = QtCore.QMimeData()

        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(event.pos() - self.rect().topLeft())

        dropAction = drag.start(QtCore.Qt.MoveAction)

    def mousePressEvent(self, event):
        print 'press'
Ich bekomme nur Ausgaben von "event", und zwar nur QEvent und QHoverEvent. Danach klappt Drag&Drop aber leider auch gar nicht mehr. Diese Funktion hab ich aber nur zu reinen Testzwecken aktiviert, um zu gucken, was überhaupt durch geht. Wenn ich andere Events teste, ist die natürlich auskommentiert.

Was fehlt denn da noch, damit ich Events kriege, die ich auswerten kann?

P.S.: Die Benennungen sollten doch jetzt richtig sein, oder?
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Hallo!

Danke nochmal.

Aber ich kapier das einfach nicht, auch mal mehreren Pausen und neu Anfangen nicht. Ich glaub, ich hab da einfach ein grundsätzliches Verständnisproblem, das ich auch nicht aufgelöst kriege. Ich weiß nicht, wie ich das QAbstractItemModel verknüpft kriege oder ich was überhaupt hinschreiben soll. Ich glaub, ich hab beim Coden noch nie dermaßen auf dem Schlauch gestanden.

Ich suche mal wieder verzweifelt und erfolglos nach einem Beispielcode, der mir zeigt, wie das geht. Und ich kann auch nicht recht glauben, dass es dazu wirklich nichts gibt, aber ich finde es einfach nicht. Vielleicht sehe ich es auch einfach nicht. Keine Ahnung. Ich drehe mich jedenfalls im Kreis und komme da nicht raus. Und deswegen sorry, ich muss nochmal nachfragen.

Am besten erklär ich einfach mal das Ziel, denn vielleicht ist auch mein ganzer Ansatz völliger Blödsinn.

Ich möchte, dass nach dem Verschieben die update-Methode aufgerufen wird und dort die item_id ankommt, damit der entsprechende Eintrag geändert werden kann.

Beim Text ändern klappt das ja, nur beim Verschieben halt leider noch nicht.

Dass die neue Position in row() steht, hab ich schon herausgefunden. Und takeRow(0) scheint ja das übergebene Item zu beinhalten. Tja, das waren meine jüngsten Versuche, nachdem ich mir gedacht habe, dass ich vielleicht doch keine Events brauche, und da steck ich jetzt fest.

Ich hab ja gedacht, ich könnte erst mal mit Hilfe eines Events die item_id bestimmen und die dann anschließend in der update-Methode aufrufen, z.B. mit self. Aber vielleicht brauch ich das ja gar nicht, wenn ich die item_id auch so irgendwie in der update-Methode finde.

Ich denke, ich werde mich jetzt doch mal um einen Datenbank-unabhängigen Beispiel-Code kümmern. ;-)
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

So, ich habe versucht, den Code aufs Wesentliche zu reduzieren und hoffe, es ist jetzt alles raus, was nichts mit dem Problem zu tun hat und/oder nur verwirrt. Ich denke, der Code sollte jetzt auch bei jedem ausführbar sein.

Dass der 4. Parameter in den Listen für die Items überall 0 ist, liegt daran, dass das das Feld "sortorder" darstellen soll, mit dem ich bis jetzt noch nichts gemacht habe. Das kommt dann als nächstes, wenn ich erst mal unten in der update-Methode die item_id habe und dann die sortorders für alle bestimme.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
from PyQt4 import QtGui, QtCore

class Window(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        self.resize(500, 600)
        self.setWindowTitle('ToDo-Liste')

        self.mktree()

        self.main_box = QtGui.QVBoxLayout()
        self.main_box.addWidget(self.todo_tree)

        self.layout = QtGui.QWidget()
        self.layout.setLayout(self.main_box)
        self.setCentralWidget(self.layout)




    def mktree(self):
        item_model = QtGui.QStandardItemModel()
        item_model.setHorizontalHeaderLabels([self.tr(u'Aufgaben')])

        items = {}

        result = [
            [1, 'Aufgabe 1', 'Beschreibung Aufgabe 1 Zeile 1\nBeschreibung Aufgabe 1 Zeile 2', 0],
            [2, 'Aufgabe 2', '', 0],
            [3, 'Aufgabe 3', 'Beschreibung Aufgabe 3 Zeile 1', 0],
            [4, 'Aufgabe 4', '', 0]
        ]

        for i in xrange(len(result)):
            _id, _item, _item_desc, _item_order = result[i]

            items[_id] = QtGui.QStandardItem(_item)
            items[_id].item_id = _id
            items[_id].setDragEnabled(True)
            items[_id].setDropEnabled(False)
            item_model.appendRow(items[_id])

            if _item_desc:
                item_desc = _item_desc.split('\n')

                i = 0
                for desc in item_desc:
                    i += 1
                    desc = QtGui.QStandardItem(desc)
                    desc.item_id = float("%d.%d" % (_id, i))
                    desc.setDropEnabled(False)
                    items[_id].appendRow(desc)

            desc = QtGui.QStandardItem('')
            desc.item_id = float("%d.%d" % (_id, i+1))
            items[_id].appendRow(desc)

        new_item = QtGui.QStandardItem('<Neue Aufgabe>')
        new_item.item_id = 0
        item_model.appendRow(new_item)

        self.connect(item_model, QtCore.SIGNAL('itemChanged(QStandardItem *)'), self.update)

        tree = QtGui.QTreeView()
        tree.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        tree.setAcceptDrops(True)
        tree.setModel(item_model)

        self.todo_tree = tree



    def update(self, item):
        # print dir(item)
        print item.item_id  # Hier kommt die richtige item_id, wenn ein Text geändert wurde.
        # Ich brauche dann halt, wie gesagt, noch die item_id von verschobenen Einträgen. 




app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())



Edit: Beim Verschieben spuckt die update-Methode folgende Fehlermeldung aus:

Code: Alles auswählen

Traceback (most recent call last):
  File "./tododbfree.py", line 82, in update
    print item.item_id
AttributeError: 'QStandardItem' object has no attribute 'item_id'
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Keine Ahnung, ob mich das irgendwie weiter bringt, aber wenn ich in der mktree-Funktion aus "items" "self.items" mache, bekomme ich unten im update mit

Code: Alles auswählen

self.items.items()[IRGENDEIN_INDEX][1].item_id
die item_id von dem Item an der Stelle "IRGENDEIN_INDEX" (hier im Beispiel ja 1-4).

Aber bis update weiß, was "IRGENDEIN_INDEX" konktet ist, müsste es eigentlich auch schon so "schlau" sein, direkt die item_id herauszufinden, oder? Oder bin ich da irgendwie auf der richtigen Spur?

Vielleicht kann ich ja irgendwas mit Vergleichen machen. Ich weiß nur noch nicht, was ich eigentlich vergleichen soll.

Oder brauche ich doch ein Event, das erst mal die ursprüngliche Position oder die item_id oder sowas ermittelt?
deets

Das ist alles ziemlich konvolut. Aber lauffaehig, immerhin ;)

Zuerstmal ein paar stilistische Sachen:

- spar dir die unnoetigen private-Unterstriche bei lokalen Variablen. Sie haben so keinen Sinn, wenn du die Variablen eh verwendest. Dafuer steht die Konvention naemlich bei Variablen-Namen: wenn sie nicht verwandt werden, zB bei nicht gebrauchten Uebergabeparametern.

- man iteriert in Python ueber Listen direkt, nicht via index-generierung. for id, .... in result: ist also voellig ausreichend
- du belegest die Laufvariable i mehrfach, das ist bestenfalls konfus, und schlimmstenfalls fehlertraechtig
- dein ganzes Description-Sub-Item-Zeug ist sehr verschwurbelt & funktioniert glaube ich eher durch Zufall

So, und nun zum Problem: du hast recht, der schoene Trick von mir mit der item_id klappt nicht. Ich weiss auch nicht, warum, kann nur vermuten, dass Qt sich bei Modellen das recht vorbehaelt, intern Kopien zu machen - und dadurch dann die extra Attribute verloren gehen.

Du kannst das durch 2 Sachen "heilen":

1) Ableiten von dem standard-item, steht in der Doku wie. Und dann einfach zusaetzliche Attribute definieren, wie du sie brauchst.
2) das generische data-attribut benutzen, das habe ich mal gemacht - funktioniert gut:

Code: Alles auswählen


#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
from PyQt4 import QtGui, QtCore

class Window(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        self.resize(500, 600)
        self.setWindowTitle('ToDo-Liste')

        self.mktree()

        self.main_box = QtGui.QVBoxLayout()
        self.main_box.addWidget(self.todo_tree)

        self.layout = QtGui.QWidget()
        self.layout.setLayout(self.main_box)
        self.setCentralWidget(self.layout)




    def mktree(self):
        item_model = QtGui.QStandardItemModel()
        item_model.setHorizontalHeaderLabels([self.tr(u'Aufgaben')])

        items = {}

        result = [
            [1, 'Aufgabe 1', 'Beschreibung Aufgabe 1 Zeile 1\nBeschreibung Aufgabe 1 Zeile 2', 0],
            [2, 'Aufgabe 2', '', 0],
            [3, 'Aufgabe 3', 'Beschreibung Aufgabe 3 Zeile 1', 0],
            [4, 'Aufgabe 4', '', 0]
        ]

        for id, name, desc, order in result:

            item = QtGui.QStandardItem(name)
            item.setDragEnabled(True)
            item.setDropEnabled(False)
            item.setData(id)
            item_model.appendRow(item)
            items[id] = item

        self.items = items
        new_item = QtGui.QStandardItem('<Neue Aufgabe>')
        new_item.item_id = 0
        item_model.appendRow(new_item)

        self.connect(item_model, QtCore.SIGNAL('itemChanged(QStandardItem *)'), self.update)

        tree = QtGui.QTreeView()
        tree.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        tree.setAcceptDrops(True)
        tree.setModel(item_model)
        self.todo_tree = tree


    def update(self, item):
        print item.data().toInt()



app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Viel Erfolg
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Woah! Danke!!! Du bist wirklich meine Rettung! Ich bin hier nämlich langsam völlig verirrt und versunken und sehe in dem ganzen Gewusel wirklich nichts mehr.
deets hat geschrieben:Das ist alles ziemlich konvolut. Aber lauffaehig, immerhin ;)
Na ja, ich versuche es so einfach und unkompliziert wie möglich zu machen, mir zu helfen, und hoffe, das gelinkt mir einigermaßen. ;-) Ist nicht so einfach, immer genau zu erfassen, was ein Helfer brauchen könnte oder wissen muss, um möglichst wenig Aufwand zu haben.

Vielen Dank auch für deine stilistischen Anmerkungen!
- spar dir die unnoetigen private-Unterstriche bei lokalen Variablen. Sie haben so keinen Sinn, wenn du die Variablen eh verwendest. Dafuer steht die Konvention naemlich bei Variablen-Namen: wenn sie nicht verwandt werden, zB bei nicht gebrauchten Uebergabeparametern.
Ich hab das gemacht, weil geany das Wort "id" formatiert dargestellt hat. Und den Rest dann halt, um es einheitlich zu machen. Aber gut, wenn sich das so nicht gehört, sollte ich das wohl anders machen.

Ich hab dieses PEP8-Ding hier im Wiki gelesen und fühlte mich da doch ein wenig an Richard Stallmans "religiösen" Wahn erinnert. ;-) Aber gut, wenn man das halt so macht, dann mach ich das halt auch mal so. ;-)
- man iteriert in Python ueber Listen direkt, nicht via index-generierung. for id, .... in result: ist also voellig ausreichend
Ja, ein Überbleibsel, weil das ja eigentlich ne Datenbank-Abfrage war. Aber das mach ich dann wohl auch besser mit "...in result"?
- du belegest die Laufvariable i mehrfach, das ist bestenfalls konfus, und schlimmstenfalls fehlertraechtig
Oh, danke für den Hinweis! Ist mir gar nicht aufgefallen. ;-)
- dein ganzes Description-Sub-Item-Zeug ist sehr verschwurbelt & funktioniert glaube ich eher durch Zufall
Mit den item_ids meinst du? Das sollen eigentlich keine Komma-Zahlen sein, nur temporär. Im update wird das beim Punkt wieder getrennt. Zeigt halt nur mit einem Rutsch an, zu welchem parent das gehört und an welcher Position die Zeile steht.

Also, ich würde sagen, das soll so sein. Oder meinst du was anderes? Na ja, seh ich ja vielleicht, wenn ich deinen Code in meinen einbaue.
So, und nun zum Problem: du hast recht, der schoene Trick von mir mit der item_id klappt nicht. Ich weiss auch nicht, warum, kann nur vermuten, dass Qt sich bei Modellen das recht vorbehaelt, intern Kopien zu machen - und dadurch dann die extra Attribute verloren gehen.
Ich hatte anhand der Fehlermeldungen beim wilden Ausprobieren und so den Eindruck, als würde der Original-Eintrag gelöscht und ein neuer angelegt.

Vielen, vielen, vielen Dank jedenfalls! Du hast mir wirklich geholfen!!! :D
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Japp! Es funktioniert im Produktiv-Code! Vielen, vielen Dank! Ich wär da niemals drauf gekommen.
Die Unteritems krieg ich zwar so auf den ersten Blick nicht durch, aber da fällt mir bestimmt noch was anderes ein, wie ich die identifizieren kann.

Danke jedenfalls!
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Wenn ich

Code: Alles auswählen

item_id = float(item.data().toString())
schreibe, klappt es auch mit den Unteritems. Dann ist das Ergebnis wieder dasselbe wie vorher, nur dass es jetzt auch mit dem Verschieben klappt.

toFloat() kann ich komischerweise nicht schreiben, weil das eine lange Kommazahl ausgibt, die nur in der Nähe der richtigen Zahl liegt.

Deinen Einwand, dass das nur durch Zufall funktioniert, behalt ich auf jeden Fall mal im Hinterkopf. Mir ist nur dabei das Problem nicht klar und ich hab das ja absichtlich so gemacht, damit es so funktioniert, wie ich das will.
deets

Ich wuerde dir davon abraten, ein float als ID zu verwenden - aus genau den beobachteten Problemen. Nimm stattdessen einen String als Key.

Was die Probleme angeht: ich habe mir das nochmal angeschaut, und im Zweifel war das Problem nicht im Code, sondern meinem Verstaendnis davon. Was aber dafuer spricht, dass er schlecht verstaendlich ist, weil dauernd dieselben Namen verwandt werden usw.
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Ok, schon gemacht. ;-)

Im update brauch ich aber kurzzeitig ein float, weil ich mit

Code: Alles auswählen

if not item_id % 1:
feststelle, ob es sich um eine übergeordnetes oder untergeordnetes Item handelt. Aber ok, das ließe sich sicherlich auch anders lösen, wobei das ja an der Stelle auch wieder egal sein dürfte, weil die ID ja da nicht mehr als key verwendet, sondern verarbeitet wird. Oder?

Und die Benennungen werde ich dann wohl doch nochmal überarbeiten. ;-) Ich hatte das ja erst mit den Großbuchstaben gemacht, weil ich fand, dass es dann besser zu lesen ist.
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Sorry, jetzt war ich gerade selber verwirrt. Als Key wird die Kommazahl ja sowieso nicht verwendet. Das ist ja immer die ID aus der Datenbank. Und die ist immer int.
Oder reden wir gerade aneinander vorbei?
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Mal so ganz nebenbei, ich mache das eigentlich gerne so, dass ich Namen wiederverwende, um den RAM-Verbrauch gering zu halten. Nach meinem bisherigen Verständnis ist es nämlich so, dass ein Bereich wieder freigegeben wird, sobald nichts mehr drauf zeigt. Ist das so oder sollte ich mein Verständnis da auch mal überarbeiten?
lunar

@Sharoonaya: Solange der Speicherverbrauch kein tatsächliches, gemessenes Problem darstellt, achte nicht darauf. Oberstes Ziel sollte erst einmal lesbarer, verständlicher und leicht wartbarer Quelltext sein. Unter dieser Prämisse ist es gerade keine gute Idee, Namen wiederzuverwenden, da es das Verständnis des Quelltext erschwert. Im Idealfall sollte ein Name nur an einer einzige Stelle auf der linken Seite einer Zuweisung stehen.

Große Nachteile im Bezug auf den Speicherverbrauch bringt das sowieso nicht mit sich. Lokale Namen werden am Ende einer Funktion sowieso bereinigt, alles andere muss eh länger leben.
Sharoonaya
User
Beiträge: 13
Registriert: Samstag 2. Juli 2011, 16:04

Ok, dann werde ich das auch mal beherzigen. ;-)
Antworten