QTreeView: Daten richtig zählen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Hallo Leute,

im nachfolgenden, ausführbaren Quelltext seht ihr sehr schnell was ich vorhabe. Ich habe euch auch ein kleines Bild mitgebracht, um das ganze zu verdeutlichen. Das Bild mit der Aufschrift "Original" zeigt das an, was bei dem derzeitigen Quelltext rauskommt, wenn das Programm ausgeführt wird. Das Bild mit der Aufschrift "Erwartet" zeigt, wie ich es gerne hätte. Und da sind wir auch schon beim Thema. Mein Anliegen ist es, dass sowohl bei Child-Einträgen (was ja offensichtlich funktioniert) als auch bei Parent-Einträgen die fortlaufende Zählung in der zweiten Spalte angezeigt wird. Derzeit sieht es so aus, dass die Zahlen 0, 4 und 8 nicht neben den Parent-Einträgen in der zweiten Spalte zu finden ist, sondern drunter. Ich stecke jetzt gedanklich irgendwie fest.

Code: Alles auswählen

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

from sys import argv

from PyQt4.QtGui import QTreeView, QApplication, QAbstractItemView, \
                        QStandardItemModel, QStandardItem

class TreeModelTester(QTreeView):
    def __init__(self):

        QTreeView.__init__(self)

        # create attributes
        self.count = 0

        self.setSelectionBehavior(QAbstractItemView.SelectRows)

        # create model
        self.model = QStandardItemModel()

        # set header for model
        self.model.setHorizontalHeaderLabels(['Column 1', 'Column 2'])
        self.setModel(self.model)
        self.setUniformRowHeights(True)

        self.populate_data()

    def populate_data(self):

        for i in range(3):
            count_item = QStandardItem('{}'.format(self.count))
            parent1 = QStandardItem('Parent' )
            parent1.appendRow([count_item])

            self.count += 1
            
            for j in range(3):
                count_item = QStandardItem('{}'.format(self.count))
                child1 = QStandardItem('Child {}'.format(i*3+j))
                parent1.appendRow([child1, count_item])

                self.count += 1
               
            self.model.appendRow(parent1)      

if __name__ == '__main__':
    app = QApplication(argv)
    tester = TreeModelTester()
    tester.show()
    app.exec_()
Bild
BlackJack

@Sophus: Du hängst da als erstes eine Zeile an `parent` mit der Zahl an, deswegen ist das auch als erstes Kind von `parent` im Ergebnis. Du musst die Zahl zusammen mit `parent` an das ”parent” von `parent` hängen, genau wie Du das bei `child` ja auch machst: Zusammen mit der Nummer an das ”parent” von dem `child`:

Code: Alles auswählen

    def populate_data(self):
 
        for i in range(3):
            count_item = QStandardItem('{}'.format(self.count))
            parent = QStandardItem('Parent')
            self.model().appendRow([parent, count_item])      
 
            self.count += 1
           
            for j in range(3):
                count_item = QStandardItem('{}'.format(self.count))
                child = QStandardItem('Child {}'.format(i*3+j))
                parent.appendRow([child, count_item])
 
                self.count += 1
Edit: Du verdeckst mit dem `model`-Attribut übrigens die `model()`-Methode von `QTreeView`, was eventuell keine gute Idee ist.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@BlackJack: Besten Dank. Bei Child hatte ich keinerlei Denk-Probleme, da es ja einen Parent gib, denen die Childs ja untergeordnet sind. Aber ich konnte in meinen Gedanken den Parent nicht soweit unterordnen, dass die Zahlen auch neben dem Parent erscheinen. Das war mein Denk-Problem. Aber wir haben ein weiteres Problem. Wenn ich deine Variante benutze, dann werden leere Einträge erstellt. Was ich meine? Dazu habe ich den aktuellen (mit deiner Version) Quelltext und ein weiteres Bild hochgeladen.

UPDATE
Damit die model()-Methode der QTreeView()-Klasse nicht verdeckt wird, habe ich das Attribut self.model in self.standard_item_model umbenannt. Aber das Problem mit den leeren Child-Einträgen bleibt weiterhin bestehen.

Code: Alles auswählen

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

from sys import argv

from PyQt4.QtGui import QTreeView, QApplication, QAbstractItemView, \
                        QStandardItemModel, QStandardItem

class TreeModelTester(QTreeView):
    def __init__(self):

        QTreeView.__init__(self)

        # create attributes
        self.count = 0

        self.setSelectionBehavior(QAbstractItemView.SelectRows)

        # create model
        self.standard_item_model = QStandardItemModel()

        # set header for model
        self.standard_item_model.setHorizontalHeaderLabels(['Column 1', 'Column 2'])
        self.setModel(self.standard_item_model)
        self.setUniformRowHeights(True)

        self.populate_data()

    def populate_data(self):
 
        for i in range(3):
            count_item = QStandardItem('{}'.format(self.count))
            parent = QStandardItem('Parent')
            self.model().appendRow([parent, count_item]) 
 
            self.count += 1
           
            for j in range(3):
                count_item = QStandardItem('{}'.format(self.count))
                child = QStandardItem('Child {}'.format(i*3+j))
                parent.appendRow([child, count_item])
 
                self.count += 1
               
            self.standard_item_model.appendRow(parent)      

if __name__ == '__main__':
    app = QApplication(argv)
    tester = TreeModelTester()
    tester.show()
    app.exec_()
Bild
Zuletzt geändert von Sophus am Montag 17. Juli 2017, 15:30, insgesamt 1-mal geändert.
BlackJack

@Sophus: Nee, bei meiner Variante passiert das nicht. Ich habe die Zeile nicht kopiert und verändert sondern nach oben verschoben und verändert. :-)
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@BlackJack: Stimmt. In meinem letzten Beispiel musste ich einfach Zeile 45 löschen. Hatte einfach deine Variante kopiert, und so soweit eingefügt, dass die Zeile 45 noch bestehen blieb. Wenn die 45. Zeile gelöscht wird, dann klappt dein Beispiel wunderbar. Danke :)
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Beinahe hätte ich es vergessen. Ich habe eine weitere, allgemeine Frage. Im nachfolgenden ausführbaren Programm sehen wir, dass ich mehrere, unterschiedliche Einträge habe. Im Beispiel Sind Name, Location und Money die Parents und der Rest ist Child. Nun, wenn ich meine TreeView weiter ausbauen will, müsste ich mehrere solche Schleifen basteln. Im Grunde funktioniert die Ansicht gut. Jedoch bläht sich die Funktion mächtig auf und obendrein befürchte ich, dass ich hier eine Redundanz erzeuge. Im Grunde werden mehrere gleiche Aufgaben erledigt. Nun frage ich mich, wie man die Parenst und Childs am besten verwaltet und diese dann nur durch die eine Schleife jagt?

Code: Alles auswählen

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

from sys import argv

from PyQt4.QtGui import QTreeView, QApplication, QAbstractItemView, \
                        QStandardItemModel, QStandardItem

class TreeModelTester(QTreeView):
    def __init__(self):

        QTreeView.__init__(self)

        # create attributes
        self.count = 0

        self.setSelectionBehavior(QAbstractItemView.SelectRows)

        # create model
        self.standard_item_model = QStandardItemModel()

        # set header for model
        self.standard_item_model.setHorizontalHeaderLabels(['Column 1', 'Column 2'])
        self.setModel(self.standard_item_model)
        self.setUniformRowHeights(True)

        self.populate_data()
       
    def populate_data(self):
 
        for i in ["Name"]:
            count_item = QStandardItem('{}'.format(self.count))
            parent = QStandardItem('{}'.format(i))
            self.model().appendRow([parent, count_item])      
 
            self.count += 1
           
            for j in ["Hans", "Peter", "Sophus"]:
                count_item = QStandardItem('{}'.format(self.count))
                child = QStandardItem('{}'.format(j))
                parent.appendRow([child, count_item])
 
                self.count += 1

        for i in ["Location"]:
            count_item = QStandardItem('{}'.format(self.count))
            parent = QStandardItem('{}'.format(i))
            self.model().appendRow([parent, count_item])      
 
            self.count += 1
           
            for j in ["Tokio", "USA", "German"]:
                count_item = QStandardItem('{}'.format(self.count))
                child = QStandardItem('{}'.format(j))
                parent.appendRow([child, count_item])
 
                self.count += 1

        for i in ["Money"]:
            count_item = QStandardItem('{}'.format(self.count))
            parent = QStandardItem('{}'.format(i))
            self.model().appendRow([parent, count_item])      
 
            self.count += 1
           
            for j in ["Dollar", "Euro", "Zlotti"]:
                count_item = QStandardItem('{}'.format(self.count))
                child = QStandardItem('{}'.format(j))
                parent.appendRow([child, count_item])
 
                self.count += 1

if __name__ == '__main__':
    app = QApplication(argv)
    tester = TreeModelTester()
    tester.show()
    app.exec_()
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Meine vorübergehende Lösung wäre eine rekursive Verwendung der Funktion. Ich habe dann die Parents und Childs in Form einer Liste, bestehend aus Tuples gespeichert. Wahrscheinlich gibt es eine elegantere Lösung mit einem Wörterbuch und sieht womöglich dann auch besser aus. Mir gefällt dieser Ansatz auch nicht so ganz 100%.

Code: Alles auswählen

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

from sys import argv

from PyQt4.QtGui import QTreeView, QApplication, QAbstractItemView, \
                        QStandardItemModel, QStandardItem

DATA = [
    ("Name", [
        ("Hans", []),
        ("Peter", []),
        ("Sophus", [])
        ]),
    ("Location", [
        ("Tokio", []),
        ("USA", []),
        ("German", []),
        ]),
    ("Money", [
        ("Dollar", []),
        ("Euro", []),
        ("Zlotti", []),
        ])
    ]

class TreeModelTester(QTreeView):
    def __init__(self):

        QTreeView.__init__(self)

        # create attributes
        self.count = 0

        self.setSelectionBehavior(QAbstractItemView.SelectRows)

        # create model
        self.standard_item_model = QStandardItemModel()

        # set header for model
        self.standard_item_model.setHorizontalHeaderLabels(['Column 1', 'Column 2'])
        self.setModel(self.standard_item_model)
        self.setUniformRowHeights(True)

        self.populate_data(model_obj=self.standard_item_model, data=DATA)
       
    def populate_data(self, model_obj=None, data=None):
 
        for text, children in data:
            count_item = QStandardItem('{}'.format(self.count))
            item = QStandardItem(text)
            model_obj.appendRow([item, count_item]) 
            self.count += 1
            
            if children:
                self.populate_data(item, children)

if __name__ == '__main__':
    app = QApplication(argv)
    tester = TreeModelTester()
    tester.show()
    app.exec_()
Antworten