PySide 2学習記録(21):QTreeView jsonファイルを読み込む

7274 ワード

Python 2.7またはPython 3.7 PySide 2 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
ここでは二つの部分に分けて、前に大きな列がある二つの種類の定義はそれぞれQJson TreeItemとQJJson Modelです。ここではとりあえずこの二つの種類を無視します。QJson Modelという種類の使い方に注目するだけで、qtでは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を設定すれば表示できます。