How can I load a CSV file into a QTreeView?

*爱你&永不变心* 提交于 2021-02-11 06:29:29

问题


Note: I am a complete beginner.

I am using a pandas dataframe to import a csv file that I converted from the following table. I need to load the csv file into a QTreeView and have been unable to do so.

The output format should be:

I will have to retrieve the "Scale Type" at some point, so I would like to somehow tag it to that item, but I'm not sure if that is possible. I have tried converting my data into a pandas dataframe and loading; loading the data directly with a csv; and converting it into a dictionary with no luck.

I can hard-code that data in, but I would prefer to use a csv as I can easily change it later.

Currently using:

        model.setHeaderData(0,Qt.Horizontal,"Category")
        model.setHeaderData(1,Qt.Horizontal,"Sub Category")
        model.setHeaderData(2,Qt.Horizontal,"Test")
        self.ui.tv.setModel(model)
        self.SetContent(model)

    def SetContent(self, model):
        self.ui.tv.setModel(model)
        i=0

        for k,featuretype in features.items():
            parent1 = QStandardItem('{}'.format(k[1]))
            for item in featuretype:
                child = QStandardItem(item[0])
                if len(item[1])>0:
                    
                    for listitem in item[1]:
                        gchild=QStandardItem(listitem)
                        child.appendRow(gchild)
                parent1.appendRow(child)
            model.setItem(i,0,parent1)
            self.ui.tv.setFirstColumnSpanned(i,self.ui.tv.rootIndex(),True)
            i+=1

This only works when values are hard keyed like:

features = {('POLYGON', 'SLPR'): [('ONE WAY', ['NO', 'YES','maybe'], 'List', 3), ('CLASS', ['INTERSTATE', 'PRIMARY', 'RESIDENTIAL', 'SECONDARY', 'SERVICE', 'STATE HWY', 'TERTIARY', 'TRACK', 'US HWY'], 'List', 11)]

But it doesn't work with dictionary objects I create from the csv or dataframe, and I get the "String Index out of Range Error".

I also found this code, which would have been great. But it gives me duplicates and the parents only.

            reader = csv.reader(f)
            for row in reader:
                item = QTreeWidgetItem(self.ui.tv, row)
                print(row)


回答1:


Below is a demo script which should do most of what you asked for. It cannot quite produce the same layout as in your second screenshot, but the structure is the same. The csv file is converted to nested dicts/lists, which can be saved to a json file. It's also possible to load the json file directly. I assumed your csv file looks like this:

"Test Category","Sub Category","Test Type","Scale Type"
"Premorbid Func.","SIMPLE","Actual","Scale"
"Premorbid Func.","SIMPLE","Predicted","Scale"
"Premorbid Func.","COMPL Montanist","TEST","Scale"
"Premorbid Func.","COMPL Montanist","Actual","Scale"
"Premorbid Func.","COMPL Montanist","Predicted","Scale"
"Intellect","WAIS-IV","WAIS-IV","T Score"
"Intellect","WAIS-IV","VCI","T Score"
"Intellect","WAIS-IV","Similarities","T Score"
"Intellect","WAIS-IV","Vocabulary","T Score"
"Attention","TOVA","RT","Scale"
"Attention","TOVA","RTV","Scale"
"Attention","DV","T","T Score"

Here is what the tree-view looks like:

enter image description here

Demo script:

import sys, os, csv, json
from collections import defaultdict
from PyQt5 import QtCore, QtGui, QtWidgets

class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.buttonLoad = QtWidgets.QPushButton('Load Data')
        self.buttonLoad.clicked.connect(self.handleProcessData)
        self.buttonSave = QtWidgets.QPushButton('Save Data')
        self.buttonSave.clicked.connect(self.handleSaveData)
        self.buttonSave.setEnabled(False)
        self.tree = QtWidgets.QTreeView()
        layout = QtWidgets.QGridLayout(self)
        layout.addWidget(self.tree, 0, 0, 1, 2)
        layout.addWidget(self.buttonLoad, 1, 0)
        layout.addWidget(self.buttonSave, 1, 1)
        self.data = None

    def loadData(self):
        path, ok = QtWidgets.QFileDialog.getOpenFileName(
            self, 'Open CSV/JSON', '.', filter='Data Files (*.csv *.json)')
        if ok:
            with open(path) as stream:
                if os.path.splitext(path)[1] == '.json':
                    self.data = json.load(stream)
                else:
                    reader = csv.reader(stream)
                    # ignore the header
                    next(reader)
                    # convert to nested dicts/lists
                    self.data = defaultdict(lambda: defaultdict(list))
                    for record in reader:
                        self.data[record[0]][record[1]].append(record[2:])

    def handleProcessData(self):
        self.loadData()
        if self.data is not None:
            model = QtGui.QStandardItemModel(self.tree)
            model.setHorizontalHeaderLabels(('Category', 'Type', 'Scale'))
            self.tree.setModel(model)
            self.tree.setColumnWidth(0, 200)
            root = self.tree.rootIndex()
            for row, (text, values) in enumerate(self.data.items()):
                category = QtGui.QStandardItem(text)
                model.appendRow(category)
                self.tree.setFirstColumnSpanned(row, root, True)
                for row, (text, values) in enumerate(values.items()):
                    subcategory = QtGui.QStandardItem(text)
                    for value in values:
                        subcategory.appendRow([
                            QtGui.QStandardItem(),
                            QtGui.QStandardItem(value[0]),
                            QtGui.QStandardItem(value[1]),
                            ])
                    category.appendRow(subcategory)
                    self.tree.setFirstColumnSpanned(
                        row, category.index(), True)
            self.tree.expandAll()
            self.buttonSave.setEnabled(True)

    def handleSaveData(self):
        path, ok = QtWidgets.QFileDialog.getSaveFileName(
            self, 'Save JSON', '.', filter='JSON Files (*.json)')
        if ok:
            with open(path, 'w') as stream:
                json.dump(self.data, stream, indent=2)


if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setWindowTitle('Test')
    window.setGeometry(600, 100, 540, 480)
    window.show()
    sys.exit(app.exec_())


来源:https://stackoverflow.com/questions/66041858/how-can-i-load-a-csv-file-into-a-qtreeview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!