Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用QTreeView编辑词典_Python_Dictionary_Pyqt_Qtreeview - Fatal编程技术网

Python 使用QTreeView编辑词典

Python 使用QTreeView编辑词典,python,dictionary,pyqt,qtreeview,Python,Dictionary,Pyqt,Qtreeview,我有一个简化的代码示例,其中只使用一个按钮创建了一个窗口 按下它将弹出一个Qt对话框TestDialog,它将Python字典作为参数。此词典显示在对话框内可编辑的QTreeView中 更改某些值后,可以单击“确定”或“取消”接受或放弃更改。对话框关闭后,我的目的是从主窗口检索修改过的字典,调用dialog.get_data(),现在只返回原始的未修改字典。单击Ok按钮后,检索到的字典将打印到标准输出 我的问题是,当树状视图被修改时,如何修改字典?是否有一种方法可以自动附加要在每个项目修改上

我有一个简化的代码示例,其中只使用一个按钮创建了一个窗口

按下它将弹出一个Qt对话框
TestDialog
,它将Python字典作为参数。此词典显示在对话框内可编辑的
QTreeView

更改某些值后,可以单击“确定”或“取消”接受或放弃更改。对话框关闭后,我的目的是从主窗口检索修改过的字典,调用
dialog.get_data()
,现在只返回原始的未修改字典。单击Ok按钮后,检索到的字典将打印到标准输出

我的问题是,当树状视图被修改时,如何修改字典?是否有一种方法可以自动附加要在每个项目修改上执行的功能?因此,当编辑树视图中的
float
时,相应的值将在字典中更新为float

词典没有固定大小,其类型可能会更改。但是类型列表是有限的和已知的,例如,可以减少为{
int
str
float
Other
}。也可以假设父项不应是可编辑的,子项仅在第二列中可编辑,正如下面的示例所示

以下是我的代码:

import sys
from PyQt4 import QtGui, QtCore, uic
from copy import deepcopy


class TestDialog(QtGui.QDialog):
    def __init__(self, data):

        super(TestDialog, self).__init__()

        self.data = deepcopy(data)

        # Layout
        btOk = QtGui.QPushButton("OK")
        btCancel = QtGui.QPushButton("Cancel")
        self.tree = QtGui.QTreeView()
        hbox = QtGui.QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(btOk)
        hbox.addWidget(btCancel)
        vbox = QtGui.QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(self.tree)
        self.setLayout(vbox)
        self.setGeometry(300, 300, 600, 400)

        # Button signals
        btCancel.clicked.connect(self.reject)
        btOk.clicked.connect(self.accept)

        # Tree view
        self.tree.setModel(QtGui.QStandardItemModel())
        self.tree.setAlternatingRowColors(True)
        self.tree.setSortingEnabled(True)
        self.tree.setHeaderHidden(False)
        self.tree.setSelectionBehavior(QtGui.QAbstractItemView.SelectItems)

        self.tree.model().setHorizontalHeaderLabels(['Parameter', 'Value'])

        for x in self.data:
            if not self.data[x]:
                continue
            parent = QtGui.QStandardItem(x)
            parent.setFlags(QtCore.Qt.NoItemFlags)
            for y in self.data[x]:
                value = self.data[x][y]
                child0 = QtGui.QStandardItem(y)
                child0.setFlags(QtCore.Qt.NoItemFlags |
                                QtCore.Qt.ItemIsEnabled)
                child1 = QtGui.QStandardItem(str(value))
                child1.setFlags(QtCore.Qt.ItemIsEnabled |
                                QtCore.Qt.ItemIsEditable |
                                ~ QtCore.Qt.ItemIsSelectable)
                parent.appendRow([child0, child1])
            self.tree.model().appendRow(parent)

        self.tree.expandAll()

    def get_data(self):
        return self.data

class Other(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return '(%s, %s)' % (self.x, self.y)

class Example(QtGui.QWidget):

    def __init__(self):

        super(Example, self).__init__()

        btn = QtGui.QPushButton('Button', self)
        btn.resize(btn.sizeHint())
        btn.clicked.connect(self.show_dialog)

        self.data = {}
        # This example will be hidden (has no parameter-value pair)
        self.data['example0'] = {}
        # A set example with an integer and a string parameters
        self.data['example1'] = {}
        self.data['example1']['int'] = 14
        self.data['example1']['str'] = 'asdf'
        # A set example with a float and other non-conventional type
        self.data['example2'] = {}
        self.data['example2']['float'] = 1.2
        self.data['example2']['other'] = Other(4, 8)

    def show_dialog(self):
        dialog = TestDialog(self.data)
        accepted = dialog.exec_()
        if not accepted:
            return
        self.data = deepcopy(dialog.get_data())
        print self.data


if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

您可以连接到模型的信号:

处理程序的外观如下所示:

    def handleItemChanged(self, item):
        parent = self.data[item.parent().text()]
        key = item.parent().child(item.row(), 0).text()
        parent[key] = type(parent[key])(item.text())
请注意,使用
type
转换值不一定适用于像
Other
这样的自定义类。因此,您必须确保此类类的构造函数可以转换字符串表示,或者在将字符串传递给构造函数之前将其解析为适当的参数

还请注意,在上面的示例代码中,我没有费心处理
QString
值。如果使用Python3,这不是问题,因为默认情况下,它们会自动转换为Python字符串或从Python字符串转换而来。但对于Python 2,您可以通过执行以下操作来打开此行为:

import sip
sip.setapi('QString', 2)
from PyQt4 import QtGui, QtCore, uic
有关此操作的详细信息,请参阅中的

import sip
sip.setapi('QString', 2)
from PyQt4 import QtGui, QtCore, uic