Python PyQt5 / JSON-AttributeError:“ NoneType”对象没有属性“ setText”

时间:2018-10-20 07:09:03

标签: python json pyqt

我在添加,加载和删除JSON文件中的脚本时遇到了麻烦,我只能编辑JSON中的两行项目,只能在加载JSON之后添加内容在GUI中,暂时不删除任​​何东西。

这是代码和JSON文件:

from PyQt5 import QtCore, QtGui, QtWidgets

import json

class Ui_Dialog(object):

    def botao_adicionar_clicked(self):
        QtWidgets.QTreeWidgetItem(self.lista_de_itens)

        with open('data.json', 'r') as file:
            data = json.load(file)
            for item in data['database']:
                num_id = int(item["num"])
                print(num_id + 1)

        item_input = self.box_item.text()
        valor_input = self.box_valor.text()
        unidades_input = self.box_unidades.text() 
        item_output = str(item_input)
        unidades_output = str(unidades_input)
        valor_output = str(valor_input)

        for item in data['database']:
            self.lista_de_itens.topLevelItem(num_id + 1).setText(0, item_output)

            self.lista_de_itens.topLevelItem(num_id + 1).setText(1, unidades_output)

            self.lista_de_itens.topLevelItem(num_id + 1).setText(2, valor_output)

        final_id = str(num_id + 1)

        item_final = {"num": final_id, "item":item_output, "unidades":unidades_output, "valor":valor_input}

        data["database"].append(item_final)

        with open('data.json', 'w') as file:
            json.dump(data, file, indent=4)

    def botao_carregar_clicked(self):
        QtWidgets.QTreeWidgetItem(self.lista_de_itens)

        with open('data.json', 'r') as file:
            data = json.load(file)
            #print(data['num'].count(["num"]))
            for item in data['database']:
                num_id = int(item["num"])
                print(num_id + 1)


        for item in data['database']:
            self.lista_de_itens.topLevelItem(int(item["num"])).setText(0, item["item"])
        for unidades in data['database']:
            self.lista_de_itens.topLevelItem(int(item["num"])).setText(1, unidades["unidades"])
        for valor in data['database']:
            self.lista_de_itens.topLevelItem(int(item["num"])).setText(2, valor["valor"])

    def botao_remover_clicked(self):
        QtWidgets.QTreeWidgetItem(self.lista_de_itens)

        with open('data.json', 'r+') as file:
            data = json.load(file)

        item_input = self.box_item.text()
        valor_input = self.box_valor.text()
        unidades_input = self.box_unidades.text() 
        item_output = str(item_input)
        unidades_output = str(unidades_input)
        valor_output = str(valor_input)

        if item_output in data['item']:
            del item_output
        elif unidades_output in data['unidades']:
            del unidades_output
        elif valor_output in data['valor']:
            del valor_output
        else:
            print('Não existe no BD')

        with open('data.json', 'w') as file:
            #item_final = {"item":item_output,"unidades":unidades_output,"valor":valor_input}
            json.dump(data, file)

    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(339, 329)
        Dialog.setSizeGripEnabled(False)
        self.lista_de_itens = QtWidgets.QTreeWidget(Dialog)
        self.lista_de_itens.setGeometry(QtCore.QRect(10, 10, 321, 191))
        self.lista_de_itens.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.lista_de_itens.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.lista_de_itens.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored)
        self.lista_de_itens.setAutoScroll(True)
        self.lista_de_itens.setIndentation(1)
        self.lista_de_itens.setRootIsDecorated(False)
        self.lista_de_itens.setUniformRowHeights(True)
        self.lista_de_itens.setItemsExpandable(False)
        self.lista_de_itens.setAnimated(False)
        self.lista_de_itens.setWordWrap(True)
        self.lista_de_itens.setExpandsOnDoubleClick(False)
        self.lista_de_itens.setObjectName("lista_de_itens")

        QtWidgets.QTreeWidgetItem(self.lista_de_itens)

        self.lista_de_itens.header().setVisible(True)
        self.lista_de_itens.header().setCascadingSectionResizes(False)
        self.lista_de_itens.header().setDefaultSectionSize(94)
        self.lista_de_itens.header().setHighlightSections(False)
        self.lista_de_itens.header().setMinimumSectionSize(35)
        self.lista_de_itens.header().setSortIndicatorShown(False)
        self.lista_de_itens.header().setStretchLastSection(False)

        self.box_item = QtWidgets.QLineEdit(Dialog)
        self.box_item.setGeometry(QtCore.QRect(10, 210, 321, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(14)
        self.box_item.setFont(font)
        self.box_item.setPlaceholderText("Item")
        self.box_item.setObjectName("box_item")

        self.box_unidades = QtWidgets.QLineEdit(Dialog)
        self.box_unidades.setGeometry(QtCore.QRect(10, 250, 151, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(14)
        self.box_unidades.setFont(font)
        self.box_unidades.setPlaceholderText("Unidades")
        self.box_unidades.setObjectName("box_unidades")

        self.box_valor = QtWidgets.QLineEdit(Dialog)
        self.box_valor.setGeometry(QtCore.QRect(180, 250, 151, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(14)
        self.box_valor.setFont(font)
        self.box_valor.setPlaceholderText("Valor")
        self.box_valor.setObjectName("box_valor")

        self.botao_carregar = QtWidgets.QPushButton(Dialog)
        self.botao_carregar.setGeometry(QtCore.QRect(121, 290, 111, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(16)
        self.botao_carregar.setFont(font)
        self.botao_carregar.setText("Carregar")
        self.botao_carregar.setObjectName("botao_carregar")

        self.botao_carregar.clicked.connect(self.botao_carregar_clicked)

        self.botao_adicionar = QtWidgets.QPushButton(Dialog)
        self.botao_adicionar.setGeometry(QtCore.QRect(11, 290, 101, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(16)
        self.botao_adicionar.setFont(font)
        self.botao_adicionar.setText("Adicionar")
        self.botao_adicionar.setObjectName("botao_adicionar")

        self.botao_adicionar.clicked.connect(self.botao_adicionar_clicked)

        self.botao_remover = QtWidgets.QPushButton(Dialog)
        self.botao_remover.setGeometry(QtCore.QRect(240, 290, 91, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(16)
        self.botao_remover.setFont(font)
        self.botao_remover.setText("Remover")
        self.botao_remover.setObjectName("botao_remover")

        self.botao_remover.clicked.connect(self.botao_remover_clicked)

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.lista_de_itens.setSortingEnabled(False)
        self.lista_de_itens.headerItem().setText(0, _translate("Dialog", "Item"))
        self.lista_de_itens.headerItem().setText(1, _translate("Dialog", "Unidades"))
        self.lista_de_itens.headerItem().setText(2, _translate("Dialog", "Valor"))
        __sortingEnabled = self.lista_de_itens.isSortingEnabled()
        self.lista_de_itens.setSortingEnabled(False)
        self.lista_de_itens.topLevelItem(0).setText(0, _translate("Dialog", "Test"))
        self.lista_de_itens.topLevelItem(0).setText(1, _translate("Dialog", "1000"))
        self.lista_de_itens.topLevelItem(0).setText(2, _translate("Dialog", "2,99"))
        self.lista_de_itens.setSortingEnabled(__sortingEnabled)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

至少加载并可以添加内容的JSON:

{
    "database": [
        {
            "num": "0",
            "item": "Test2",
            "unidades": "200",
            "valor": "2,99"
        },
        {
            "num": "1",
            "item": "Test3",
            "unidades": "31",
            "valor": "5,99"
        }
    ]
}

无效的JSON:

{
    "database": [
        {
            "num": "0",
            "item": "Test2",
            "unidades": "200",
            "valor": "2,99"
        },
        {
            "num": "1",
            "item": "Test3",
            "unidades": "31",
            "valor": "5,99"
        },
        {
            "num": "2",
            "item": "Test4",
            "unidades": "31",
            "valor": "5,99"
        }
    ]
}

在此先感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

您的主要问题是您试图访问的项目不存在,因此QTreeWidget将返回None,从而导致您遇到错误。在您必须订购的第一个链接中,Qt Designer不提供窗口小部件,而是提供一个填充窗口小部件的类,因此,我建议您创建另一个继承自窗口小部件的类,并使用上一个类进行填充。

要解决该问题,在您指示的任务中,您始终将必须填写文件中的项目,反之亦然,因此最好创建2种方法来执行此操作。另一方面,我创建了一个自定义的QTreeWidgetItem来支持这4个项目,因此添加或删除它们都可以实现加载和保存的功能。但是删除的任务令人困惑,因为我不了解如何识别要删除的行,因此我提出了一种新的方法:选中的行将被删除,为此,您必须先单击该行,然后单击该按钮。

from PyQt5 import QtCore, QtGui, QtWidgets
import json


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(339, 329)
        Dialog.setSizeGripEnabled(False)
        self.lista_de_itens = QtWidgets.QTreeWidget(Dialog)
        self.lista_de_itens.setGeometry(QtCore.QRect(10, 10, 321, 191))
        self.lista_de_itens.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.lista_de_itens.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.lista_de_itens.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored)
        self.lista_de_itens.setAutoScroll(True)
        self.lista_de_itens.setIndentation(1)
        self.lista_de_itens.setRootIsDecorated(False)
        self.lista_de_itens.setUniformRowHeights(True)
        self.lista_de_itens.setItemsExpandable(False)
        self.lista_de_itens.setAnimated(False)
        self.lista_de_itens.setWordWrap(True)
        self.lista_de_itens.setExpandsOnDoubleClick(False)
        self.lista_de_itens.setObjectName("lista_de_itens")

        self.lista_de_itens.header().setVisible(True)
        self.lista_de_itens.header().setCascadingSectionResizes(False)
        self.lista_de_itens.header().setDefaultSectionSize(94)
        self.lista_de_itens.header().setHighlightSections(False)
        self.lista_de_itens.header().setMinimumSectionSize(35)
        self.lista_de_itens.header().setSortIndicatorShown(False)
        self.lista_de_itens.header().setStretchLastSection(False)

        self.box_item = QtWidgets.QLineEdit(Dialog)
        self.box_item.setGeometry(QtCore.QRect(10, 210, 321, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(14)
        self.box_item.setFont(font)
        self.box_item.setPlaceholderText("Item")
        self.box_item.setObjectName("box_item")

        self.box_unidades = QtWidgets.QLineEdit(Dialog)
        self.box_unidades.setGeometry(QtCore.QRect(10, 250, 151, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(14)
        self.box_unidades.setFont(font)
        self.box_unidades.setPlaceholderText("Unidades")
        self.box_unidades.setObjectName("box_unidades")

        self.box_valor = QtWidgets.QLineEdit(Dialog)
        self.box_valor.setGeometry(QtCore.QRect(180, 250, 151, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(14)
        self.box_valor.setFont(font)
        self.box_valor.setPlaceholderText("Valor")
        self.box_valor.setObjectName("box_valor")

        self.botao_carregar = QtWidgets.QPushButton(Dialog)
        self.botao_carregar.setGeometry(QtCore.QRect(121, 290, 111, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(16)
        self.botao_carregar.setFont(font)
        self.botao_carregar.setObjectName("botao_carregar")

        self.botao_adicionar = QtWidgets.QPushButton(Dialog)
        self.botao_adicionar.setGeometry(QtCore.QRect(11, 290, 101, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(16)
        self.botao_adicionar.setFont(font)
        self.botao_adicionar.setObjectName("botao_adicionar")

        self.botao_remover = QtWidgets.QPushButton(Dialog)
        self.botao_remover.setGeometry(QtCore.QRect(240, 290, 91, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(16)
        self.botao_remover.setFont(font)
        self.botao_remover.setObjectName("botao_remover")
        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.lista_de_itens.setSortingEnabled(False)
        self.lista_de_itens.headerItem().setText(0, _translate("Dialog", "Item"))
        self.lista_de_itens.headerItem().setText(1, _translate("Dialog", "Unidades"))
        self.lista_de_itens.headerItem().setText(2, _translate("Dialog", "Valor"))
        __sortingEnabled = self.lista_de_itens.isSortingEnabled()
        self.lista_de_itens.setSortingEnabled(False)
        self.lista_de_itens.setSortingEnabled(__sortingEnabled)
        self.botao_carregar.setText(_translate("Dialog", "Carregar"))
        self.botao_adicionar.setText(_translate("Dialog", "Adicionar"))
        self.botao_remover.setText(_translate("Dialog", "Remover"))


class TreeWidgetItem(QtWidgets.QTreeWidgetItem):
    def __init__(self, num, item, unidades, valor):
        super(TreeWidgetItem, self).__init__([item, unidades, valor])
        self._num = num


class Dialog(QtWidgets.QDialog, Ui_Dialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)
        self.setupUi(self)
        self.botao_carregar.clicked.connect(self.botao_carregar_clicked)
        self.botao_adicionar.clicked.connect(self.botao_adicionar_clicked)
        self.botao_remover.clicked.connect(self.botao_remover_clicked)

    @QtCore.pyqtSlot()
    def botao_carregar_clicked(self):
        # remove all items
        self.lista_de_itens.clear()
        # load new items from file
        self.carregar_itens_do_arquivo()

    @QtCore.pyqtSlot()
    def botao_adicionar_clicked(self):
        item_input = self.box_item.text()
        valor_input = self.box_valor.text()
        unidades_input = self.box_unidades.text()
        if not item_input or not valor_input or not unidades_input:
            print("empty fields")
            return
        num_input = max([self.lista_de_itens.topLevelItem(i)._num for i in range(self.lista_de_itens.topLevelItemCount())] + [-1])+1
        it = TreeWidgetItem(num_input, item_input, valor_input, unidades_input)
        self.lista_de_itens.addTopLevelItem(it)
        self.salvar_itens_em_um_arquivo()
        self.box_item.clear()
        self.box_valor.clear()
        self.box_unidades.clear()

    @QtCore.pyqtSlot()
    def botao_remover_clicked(self):
        for it in reversed(self.lista_de_itens.selectedItems()):
            i = self.lista_de_itens.indexOfTopLevelItem(it)
            it_ = self.lista_de_itens.takeTopLevelItem(i)
            del it_
        self.salvar_itens_em_um_arquivo()

    def carregar_itens_do_arquivo(self):
        with open('data.json', 'r') as file:
            data = json.load(file)
            for e in data['database']:
                it = TreeWidgetItem(int(e["num"]), e["item"], e["unidades"], e["valor"])
                self.lista_de_itens.addTopLevelItem(it)

    def salvar_itens_em_um_arquivo(self):
        data = { "database": [] }
        for i in range(self.lista_de_itens.topLevelItemCount()):
            it = self.lista_de_itens.topLevelItem(i)
            row = {"num": str(it._num), "item" : it.text(0), "unidades": it.text(1), "valor": it.text(2)}
            data["database"].append(row)

        with open('data.json', 'w') as file:
            json.dump(data, file, indent=4)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Dialog()
    w.show()
    sys.exit(app.exec_())