PySide2学习记录(二十一):QTreeView载入json文件

Python2.7 或 Python3.7
PySide2 Version: 5.11.2
官方文档:http://doc.qt.io/qtforpython/index.html
参考代码:https://github.com/dridk/QJsonModel/blob/master/qjsonmodel.py

代码

# -*- coding:utf-8 -*-
from PySide2 import QtWidgets, QtCore, QtGui
import sys
import json


class QJsonTreeItem(object):
    def __init__(self, parent=None):
        self._parent = parent

        self._key = ""
        self._value = ""
        self._type = None
        self._children = list()

    def appendChild(self, item):
        self._children.append(item)

    def child(self, row):
        return self._children[row]

    def parent(self):
        return self._parent

    def childCount(self):
        return len(self._children)

    def row(self):
        return (
            self._parent._children.index(self)
            if self._parent else 0
        )

    @property
    def key(self):
        return self._key

    @key.setter
    def key(self, key):
        self._key = key

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, value):
        self._value = value

    @property
    def type(self):
        return self._type

    @type.setter
    def type(self, typ):
        self._type = typ

    @classmethod
    def load(self, value, parent=None, sort=True):
        rootItem = QJsonTreeItem(parent)
        rootItem.key = "root"

        if isinstance(value, dict):
            items = (
                sorted(value.items())
                if sort else value.items()
            )

            for key, value in items:
                child = self.load(value, rootItem)
                child.key = key
                child.type = type(value)
                rootItem.appendChild(child)

        elif isinstance(value, list):
            for index, value in enumerate(value):
                child = self.load(value, rootItem)
                child.key = str(index)
                child.type = type(value)
                rootItem.appendChild(child)

        else:
            rootItem.value = value
            rootItem.type = type(value)

        return rootItem


class QJsonModel(QtCore.QAbstractItemModel):
    def __init__(self, parent=None):
        super(QJsonModel, self).__init__(parent)

        self._rootItem = QJsonTreeItem()
        self._headers = ("key", "value")

    def load(self, document):
        """Load from dictionary
        Arguments:
            document (dict): JSON-compatible dictionary
        """

        assert isinstance(document, (dict, list, tuple)), (
            "`document` must be of dict, list or tuple, "
            "not %s" % type(document)
        )

        self.beginResetModel()

        self._rootItem = QJsonTreeItem.load(document)
        self._rootItem.type = type(document)

        self.endResetModel()

        return True

    def json(self, root=None):
        """Serialise model as JSON-compliant dictionary
        Arguments:
            root (QJsonTreeItem, optional): Serialise from here
                defaults to the the top-level item
        Returns:
            model as dict
        """

        root = root or self._rootItem
        return self.genJson(root)

    def data(self, index, role):
        if not index.isValid():
            return None

        item = index.internalPointer()

        if role == QtCore.Qt.DisplayRole:
            if index.column() == 0:
                return item.key

            if index.column() == 1:
                return item.value

        elif role == QtCore.Qt.EditRole:
            if index.column() == 1:
                return item.value

    def setData(self, index, value, role):
        if role == QtCore.Qt.EditRole:
            if index.column() == 1:
                item = index.internalPointer()
                item.value = str(value)

                self.dataChanged.emit(index, index, [QtCore.Qt.EditRole])

                return True

        return False

    def headerData(self, section, orientation, role):
        if role != QtCore.Qt.DisplayRole:
            return None

        if orientation == QtCore.Qt.Horizontal:
            return self._headers[section]

    def index(self, row, column, parent=QtCore.QModelIndex()):
        if not self.hasIndex(row, column, parent):
            return QtCore.QModelIndex()

        if not parent.isValid():
            parentItem = self._rootItem
        else:
            parentItem = parent.internalPointer()

        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QtCore.QModelIndex()

    def parent(self, index):
        if not index.isValid():
            return QtCore.QModelIndex()

        childItem = index.internalPointer()
        parentItem = childItem.parent()

        if parentItem == self._rootItem:
            return QtCore.QModelIndex()

        return self.createIndex(parentItem.row(), 0, parentItem)

    def rowCount(self, parent=QtCore.QModelIndex()):
        if parent.column() > 0:
            return 0

        if not parent.isValid():
            parentItem = self._rootItem
        else:
            parentItem = parent.internalPointer()

        return parentItem.childCount()

    def columnCount(self, parent=QtCore.QModelIndex()):
        return 2

    def flags(self, index):
        flags = super(QJsonModel, self).flags(index)

        if index.column() == 1:
            return QtCore.Qt.ItemIsEditable | flags
        else:
            return flags

    def genJson(self, item):
        nchild = item.childCount()

        if item.type is dict:
            document = {}
            for i in range(nchild):
                ch = item.child(i)
                document[ch.key] = self.genJson(ch)
            return document

        elif item.type == list:
            document = []
            for i in range(nchild):
                ch = item.child(i)
                document.append(self.genJson(ch))
            return document

        else:
            return item.value


def loaddata():
    model = QJsonModel()
    with open('/Users/wzh/pythonfile/QtFile/population.json', 'r') as f:
        data = json.load(f)
        model.load(data)
    return model


app = QtWidgets.QApplication()
window = QtWidgets.QWidget()
window.setFixedSize(650, 500)
layout = QtWidgets.QHBoxLayout(window)
treeview = QtWidgets.QTreeView(window)

treeview.setModel(loaddata())
# 设置第一列的宽度为200
treeview.setColumnWidth(0, 200)

layout.addWidget(treeview)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())

效果图:

图1

这里分两部分,前面有一大串的两个类的定义分别是QJsonTreeItem和QJsonModel,这里我们先暂时不管这两个类(具体细节访问顶部参考链接)。只需要先关注QJsonModel这个类的用法,由于qt中没有提供装载json数据的模型,所以我从网上找到了别人已经写好的模型,用来装载json数据,用法也很简单。

    model = QJsonModel()
    with open('/Users/wzh/pythonfile/QtFile/population.json', 'r') as f:
        data = json.load(f)
        model.load(data)

先定义一个model,然后打开json文件的文件描述符,使用python中的json模块读出数据,json.load()会完成文件内容的读取和反序列化操作,data是字典类型,然后使用model中的load函数装载数据到model中就可以了,最后在view中设置这个model就可以显示了。

你可能感兴趣的:(PySide2学习记录(二十一):QTreeView载入json文件)