如何保存PySide树视图模型结构

时间:2013-12-06 09:10:18

标签: python qt pyqt pyside qtreeview

以下是其他SO问题QTreeView with custom items上的链接,其中是QTreeView示例。

请在这个例子中有人解释一下,如何从treeview中保存树结构。

  1. 是否可以从中提取标签名称的QAbstractItemModel类以及我可以再次加载的结构?

  2. 如果是这样,我怎么能访问节点?除了索引以外的任何其他方式吗?

  3. 编辑(来自链接):

    import sys
    from PySide import QtGui, QtCore
    
    
    #-------------------------------------------------------------------------------
    # my test data
    class Icon():
        def __init__(self, icon, tooltip):
            self.pixmap = QtGui.QPixmap(icon)
            self.tooltip = tooltip
    
    #-------------------------------------------------------------------------------
    # my test data
    class MyData():
        def __init__(self, txt, parent=None):
            self.txt = txt
            self.tooltip = None
            self.parent = parent
            self.child = []
            self.icon = []
            self.index = None
            self.widget = None
    
        #---------------------------------------------------------------------------
        def position(self):
            position = 0
            if self.parent is not None:
                count = 0
                children = self.parent.child
                for child in children:
                    if child == self:
                        position = count
                        break
                    count += 1
            return position
    
        #---------------------------------------------------------------------------
        # test initialization
        @staticmethod
        def init():
            root = MyData("root")
            root.icon.append(Icon("icon.png", "ToolTip icon.png"))
            root.tooltip = "root tooltip"
            for i in range(0, 2):
                child1 = MyData("child %i" % (i), root)
                child1.icon.append(Icon("icon1.png", "ToolTip icon1.png"))
                child1.tooltip = "child1 tooltip"
                root.child.append(child1)
                for x in range(0, 2):
                    child2 = MyData("child %i %i" % (i, x), child1)
                    child2.icon.append(Icon("icon1.png", "ToolTip icon1.png"))
                    child2.icon.append(Icon("icon2.png", "ToolTip icon2.png"))
                    child2.tooltip = "child2 tooltip"
                    child1.child.append(child2)
    
            return root
    
    #-------------------------------------------------------------------------------
    class TreeViewModel(QtCore.QAbstractItemModel):
        #---------------------------------------------------------------------------
        def __init__(self, tree):
            super(TreeViewModel, self).__init__()
            self.__tree = tree
            self.__current = tree
            self.__view = None
    
        #---------------------------------------------------------------------------
        def flags(self, index):
            flag = QtCore.Qt.ItemIsEnabled
            if index.isValid():
                flag |= QtCore.Qt.ItemIsSelectable \
                     | QtCore.Qt.ItemIsUserCheckable \
                     | QtCore.Qt.ItemIsEditable \
                     | QtCore.Qt.ItemIsDragEnabled \
                     | QtCore.Qt.ItemIsDropEnabled
            return flag
    
        #---------------------------------------------------------------------------
        def index(self, row, column, parent=QtCore.QModelIndex()):
            node = QtCore.QModelIndex()
            if parent.isValid():
                nodeS = parent.internalPointer()
                nodeX = nodeS.child[row]
                node = self.__createIndex(row, column, nodeX)
            else:
                node = self.__createIndex(row, column, self.__tree)
            return node
    
        #---------------------------------------------------------------------------
        def parent(self, index):
            node = QtCore.QModelIndex()
            if index.isValid():
                nodeS = index.internalPointer()
                parent = nodeS.parent
                if parent is not None:
                    node = self.__createIndex(parent.position(), 0, parent)
            return node
    
        #---------------------------------------------------------------------------
        def rowCount(self, index=QtCore.QModelIndex()):
            count = 1
            node = index.internalPointer()
            if node is not None:
                count = len(node.child)
            return count
    
        #---------------------------------------------------------------------------
        def columnCount(self, index=QtCore.QModelIndex()):
            return 1
    
        #---------------------------------------------------------------------------
        def data(self, index, role=QtCore.Qt.DisplayRole):
            data = None
            return data
    
        #---------------------------------------------------------------------------
        def setView(self, view):
            self.__view = view
    
        #---------------------------------------------------------------------------
        def __createIndex(self, row, column, node):
            if node.index == None:
                index = self.createIndex(row, column, node)
                node.index = index
            if node.widget is None:
                node.widget = Widget(node)
                self.__view.setIndexWidget(index, node.widget)
            return node.index
    
    
    #-------------------------------------------------------------------------------
    class TreeView(QtGui.QTreeView):
        #---------------------------------------------------------------------------
        def __init__(self, model, parent=None):
            super(TreeView, self).__init__(parent)
            self.setModel(model)
            model.setView(self)
            root = model.index(0, 0)
            self.setCurrentIndex(root)
            self.setHeaderHidden(True)
    
        #---------------------------------------------------------------------------
        def keyPressEvent(self, event):
            k = event.key()
            if k == QtCore.Qt.Key_F2:
                self.__editMode()
    
            super(TreeView, self).keyPressEvent(event)
    
        #---------------------------------------------------------------------------
        def __editMode(self):
            index = self.currentIndex()
            node = index.internalPointer()
            node.widget.editMode(True, True)
    
    
    #-------------------------------------------------------------------------------
    class Label(QtGui.QLabel):
        #---------------------------------------------------------------------------
        def __init__(self, parent, text):
            super(Label, self).__init__(text)
            self.__parent = parent
    
        #---------------------------------------------------------------------------
        def mouseDoubleClickEvent(self, event):
            #print("mouseDoubleClickEvent")
            if self.__parent is not None:
                self.__parent.editMode(True, True)
            else:
                super(Label, self).mouseDoubleClickEvent(event)
    
    
    #-------------------------------------------------------------------------------
    class LineEdit(QtGui.QLineEdit):
        #---------------------------------------------------------------------------
        def __init__(self, parent, text):
            super(LineEdit, self).__init__(text)
            self.__parent = parent
            self.editingFinished.connect(self.__editingFinished)
    
        #---------------------------------------------------------------------------
        def keyPressEvent(self, event):
            k = event.key()
            if k == QtCore.Qt.Key_Escape:
                print("ESC 2")
                self.__editingFinished(False)
            super(LineEdit, self).keyPressEvent(event)
    
        #---------------------------------------------------------------------------
        def __editingFinished(self, bCopy=True):
            print("editingFinished")
            self.__parent.editMode(False, bCopy)
    
    #-------------------------------------------------------------------------------
    class Widget(QtGui.QWidget):
        #---------------------------------------------------------------------------
        def __init__(self, node):
            super(Widget, self).__init__()
            self.autoFillBackground()
            self.__node = node
            self.__bEditMode = False
            self.__txt = None
            self.__create(self.__node, self.__bEditMode)
    
        #---------------------------------------------------------------------------
        def __create(self, node, bEditMode):
            layout = QtGui.QHBoxLayout()
            for icon in node.icon:
                label = Label(None, node.txt)
                label.setPixmap(icon.pixmap)
                label.setToolTip("label tooltip %s %s" % (node.txt, icon.tooltip))
                layout.addWidget(label)
    
            self.__changeTxt(layout, node, bEditMode, False)
            self.setLayout(layout)
    
        #---------------------------------------------------------------------------
        def __changeTxt(self, layout, node, bEditMode, bCopy):
            if self.__txt is not None:
                if bCopy:
                    node.txt = self.__txt.text()
                if isinstance(self.__txt, LineEdit):
                    self.__txt.deselect()
                self.__txt.hide()
                layout.removeWidget(self.__txt)
                self.__txt = None
    
            if bEditMode:
                self.__txt = LineEdit(self, node.txt)
                self.__txt.setFrame(False)
                self.__txt.selectAll()
                QtCore.QTimer.singleShot(0, self.__txt, QtCore.SLOT('setFocus()'));
            else:
                self.__txt = Label(self, node.txt)
            self.__txt.setToolTip("Text tooltip %s %s" % (node.txt, node.tooltip))
            layout.addWidget(self.__txt, 1)
    
        #---------------------------------------------------------------------------
        def editMode(self, bEditMode, bCopy):
            if self.__bEditMode != bEditMode:
                self.__bEditMode = bEditMode
                layout = self.layout()
                self.__changeTxt(layout, self.__node, bEditMode, bCopy)
    
    #-------------------------------------------------------------------------------
    class MyTree(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super(MyTree, self).__init__(parent)
    
            data = MyData.init()
            frame = QtGui.QFrame();
            frame.setLayout( QtGui.QHBoxLayout() );
    
            treeViewModel = TreeViewModel(data)
            treeView = TreeView(treeViewModel)
            frame.layout().addWidget( treeView );
    
            self.setCentralWidget(frame)
    
    #-------------------------------------------------------------------------------
    def main():
        app = QtGui.QApplication(sys.argv)
        form = MyTree()
        form.show()
        app.exec_()
    
    if __name__ == '__main__':
        main()
    

1 个答案:

答案 0 :(得分:5)

你的问题很不清楚,因为你没有说出你想要保存树形结构的形式。

假设您并不真正关心,并且XML可以接受,您可以查看Qt文档中的Simple DOM Model Example

Qt文档中的大多数示例都已移植到PyQt,并提供源代码,可以从here下载。可以在examples/itemviews下找到Simple DOM Model示例。

修改

我忽略了你在使用PySide。可以找到PySide的等效移植示例here,或sources/pyside-examples/examples/itemviews下的PySide source code

<强>更新

这是一个使用xml.etree序列化树的简单示例:

import sip
sip.setapi('QString', 2)

from xml.etree import cElementTree as etree
from PyQt4 import QtGui, QtCore

class Window(QtGui.QWidget):
    def __init__(self, xml):
        QtGui.QWidget.__init__(self)
        self.tree = QtGui.QTreeWidget(self)
        self.tree.header().hide()
        self.importTree(xml)
        self.button = QtGui.QPushButton('Export', self)
        self.button.clicked[()].connect(self.exportTree)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.tree)
        layout.addWidget(self.button)

    def importTree(self, xml):
        def build(item, root):
            for element in root.getchildren():
                child = QtGui.QTreeWidgetItem(
                    item, [element.attrib['text']])
                child.setFlags(
                    child.flags() | QtCore.Qt.ItemIsEditable)
                build(child, element)
            item.setExpanded(True)
        root = etree.fromstring(xml)
        build(self.tree.invisibleRootItem(), root)

    def exportTree(self):
        def build(item, root):
            for row in range(item.childCount()):
                child = item.child(row)
                element = etree.SubElement(
                    root, 'node', text=child.text(0))
                build(child, element)
        root = etree.Element('root')
        build(self.tree.invisibleRootItem(), root)
        from xml.dom import minidom
        print(minidom.parseString(etree.tostring(root)).toprettyxml())

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window("""\
<?xml version="1.0" ?>
<root>
    <node text="Child (0)">
        <node text="Child (0)">
            <node text="Child (0)"/>
            <node text="Child (1)"/>
        </node>
        <node text="Child (1)">
            <node text="Child (0)"/>
            <node text="Child (1)"/>
        </node>
    </node>
    <node text="Child (1)">
        <node text="Child (0)">
            <node text="Child (0)"/>
            <node text="Child (1)"/>
        </node>
        <node text="Child (1)">
            <node text="Child (0)"/>
            <node text="Child (1)"/>
        </node>
    </node>
</root>
        """)
    window.setGeometry(800, 300, 300, 300)
    window.show()
    sys.exit(app.exec_())