2014-02-08 1 views
3

최근에 나는 PyQt에서 QTreeWidget을 사용하여 QDataStream을 사용하는 방법을 연구했다. 필자는 이것을 정확히 수행 한 구체적인 예제를 찾지 못했고, QDataStream에 대한 pyqt 문서는 일반적으로 꽤 부족한 것으로 보입니다. 그래서 저는 다른 사람들이 그 라인 아래 힌트를 필요로 할 때를 대비하여 여기에 빵 부스러기 흔적으로 질문을 올릴 것이라고 생각했습니다. 누군가가 뛰어 들어가서 그걸보고 싶을 때를 대비해 조금 기다릴 것이고, 나는 내 자신의 노력으로 다시 게시 할 것입니다.PyQt : QDataStream을 사용하여 네이티브 QTreeWidgets 저장

질문 : PyQt에서 QDataStream을 사용하여 QTreeWidgetItems를 원시 QT 개체로 파일에 저장 한 다음 파일을 다시 읽어서 저장 한 트리 구조를 정확하게 복원 할 수 있습니까?

에릭

답변

1

내가 미리 가서 보여주지를 내가 사용한 방법. 다행히도 내 자신의 문제가 어떻게 해결되었는지 알고 부당한 이득을 얻지는 못했을 것입니다 .-)

더 깨끗한 사람이나 더 파이썬적인 사람이 있다면 후속 조치를 환영합니다. 감사!

import sys,os.path 
from PyQt4 import QtGui, QtCore 

class TreeExperiment(QtGui.QWidget): 
    def __init__(self,parent=None): 
     QtGui.QWidget.__init__(self,parent) 

     self.tree=QtGui.QTreeWidget(self)    # 
     self.tree.setObjectName("treeWidget")   # 
     self.add_button=QtGui.QPushButton("Add", self) # Initialize a simple 
     self.save_button=QtGui.QPushButton("Save", self) # form containing a 
     gridlayout = QtGui.QGridLayout(self)    # treeWidget, an  
     gridlayout.addWidget(self.tree,1,0,1,9)   # 'Add' button, and a 
     gridlayout.addWidget(self.add_button,2,0,2,3) # 'Save' button 
     gridlayout.addWidget(self.save_button,2,3,2,3) # 
     self.tree.headerItem().setText(0,"Label")  # 


     if os.path.isfile('native_tree_save.qfile'): 
      # First look for a previously saved tree. If found, define 
      # it as a QFile named 'file', open it, and define a datastream 
      # to read from it. 
      # 
      # Each tree node is saved to and read from the file in pairs: 
      # first, the QTreeWidgetItem itself, then the number of children 
      # the item has so that the tree structure can be re-created 
      # 
      # The first item is added directly as the root for simplicity, 
      # and is sent to the function which begins the tree reconstruction 

      file = QtCore.QFile('native_tree_save.qfile') 
      file.open(QtCore.QIODevice.ReadOnly)   
      datastream = QtCore.QDataStream(file)   
      child=QtGui.QTreeWidgetItem(self.tree.invisibleRootItem()) 
      child.read(datastream) 
      num_childs=datastream.readUInt32() 
      self.restore_item(datastream,child,num_childs) 
     else: # Otherwise if this is the first use, create a root item 
      new_item=QtGui.QTreeWidgetItem(self.tree) 
      self.tree.setCurrentItem(self.tree.topLevelItem(0)) 
      self.tree.currentItem().setText(0,'root') 

     self.tree.setItemSelected(self.tree.topLevelItem(0),1) 
     self.tree.setCurrentItem(self.tree.topLevelItem(0)) 

     self.connect(self.add_button, QtCore.SIGNAL("clicked()"), self.add_item) 
     self.connect(self.save_button, QtCore.SIGNAL("clicked()"), self.save_tree) 
     self.added_item_count=0 

    def add_item(self): # Adds an item to whatever is selected 
     self.added_item_count+=1 
     label=str(self.added_item_count) 
     new_item=QtGui.QTreeWidgetItem(self.tree.currentItem()) 
     new_item.setText(0,label) 
     self.tree.setCurrentItem(new_item) 

    def restore_item(self,datastream,item,num_childs): 
     for i in range(0, num_childs): 
      child=QtGui.QTreeWidgetItem(item) 
      child.read(datastream) 
      num_childs=datastream.readUInt32() 
      self.restore_item(datastream,child,num_childs) 

    def save_item(self,item,datastream): 
     num_childs=item.childCount() 
     for i in range(0,num_childs): 
      child = item.child(i) 
      child.write(datastream) 
      num_childs=child.childCount() 
      datastream.writeUInt32(num_childs) 
      self.save_item(child,datastream) 

    def save_tree(self): 
     file = QtCore.QFile('native_tree_save.qfile') 
     file.open(QtCore.QIODevice.WriteOnly) 
     datastream = QtCore.QDataStream(file) 
     self.save_item(self.tree.invisibleRootItem(),datastream) 


if __name__=='__main__': 
    app = QtGui.QApplication(sys.argv) 
    window = TreeExperiment() 
    window.resize(200, 120) 
    window.show() 
    sys.exit(app.exec_()) 
0

QTreeWidget은 붉은 청어입니다. 저장중인 것은 일반 QAbstractItemModel (treeWidget->model())입니다. 결국 QTreeWidget은 뷰이며 모델이 내장되어 있습니다. 이제 해당 모델의 항목은 간단히 QVariant이고, 이는 단순히 파이썬 유형이며 QDataStream::operator<<으로 완전히 지원됩니다. 트리 탐색 (깊이 우선, 너비 우선 또는 다른 것)을 선택하고 트리의 항목과 깊이를 스트림으로 덤프하면됩니다. 스트림을 읽을 때 트리를 재구성하기에 충분한 정보입니다.

+0

감사합니다. 해결책에 대한 좋은 설명입니다. 잘하면 해당 항목보다는 treeWidget에 대해 말하기에 기만적 인 것이 아닙니다. 도착한 솔루션이 항목 저장에 의존하고 새로운 treeWidget의 구조를 채우는 데 사용하는 것이 정확합니다. 몇 줄의 파이썬 코드를 제공 하시겠습니까? 당신이 C++로 말하고있는 것을 보았습니다. 그러나 나는 그 연산자를 작동시킬 수 없었습니다. QDataStream 기능을 사용하는 것은 이해하는 데 시간이 걸린 트릭 중 하나였습니다. –

+0

@EricMyers 내일은, 파이썬을 가끔 사용합니다. –

2

비슷한 질문에 나는 xml로 serialize하는 간단한 데모를 작성했습니다.

동일한 코드를 QDataStream에서 작동하도록 쉽게 적용 할 수 있습니다. 난 정말 (같은 일을 달성하기 위해 여러 가지 방법으로 수십 아마가) 솔루션으로이 추천 아니지만, 적어도 동작하는 예제도 제공하지 않습니다 :

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.button = QtGui.QPushButton('Export', self) 
     self.button.clicked[()].connect(self.exportTree) 
     layout = QtGui.QVBoxLayout(self) 
     layout.addWidget(self.tree) 
     layout.addWidget(self.button) 
     self._array = QtCore.QByteArray() 
     self._buffer = QtCore.QBuffer(self._array, self) 
     self._buffer.open(QtCore.QIODevice.ReadWrite) 
     self._datastream = QtCore.QDataStream(self._buffer) 
     self.importTree(xml) 

    def importTree(self, xml): 
     def build(item, root): 
      for element in root.getchildren(): 
       child = QtGui.QTreeWidgetItem(item) 
       data = element.attrib['data'].encode('ascii') 
       self._array.swap(self._array.fromBase64(data)) 
       self._buffer.reset() 
       self._datastream >> child 
       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) 
       self._array.clear() 
       self._buffer.reset() 
       self._datastream << child 
       data = self._array.toBase64().data().decode('ascii') 
       element = etree.SubElement(root, 'node', data=data) 
       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 data="AAAAAQAAAAEAAAAJAAAAQwAB/////wAA 
       AAAAAAAAAAEAAAAKAAAAAAYAUgBlAGQ="> 
     <node data="AAAAAQAAAAEAAAAJAAAAQwAB//8AAP// 
        //8AAAAAAAEAAAAKAAAAAAgAQwB5AGEAbg=="> 
      <node data="AAAAAQAAAAEAAAAJAAAAQwAB//8AAICA 
         AAAAAAAAAAEAAAAKAAAAAAoARwByAGUAZQBu"/> 
      <node data="AAAAAQAAAAEAAAAJAAAAQwAB//8AAAAA 
         //8AAAAAAAEAAAAKAAAAAAgAQgBsAHUAZQ=="/> 
     </node> 
     <node data="AAAAAQAAAAEAAAAJAAAAQwAB/////6Wl 
        AAAAAAAAAAEAAAAKAAAAAAwATwByAGEAbgBnAGU="> 
      <node data="AAAAAQAAAAEAAAAJAAAAQwAB//+AgAAA 
         gIAAAAAAAAEAAAAKAAAAAAwAUAB1AHIAcABsAGU="/> 
      <node data="AAAAAQAAAAEAAAAJAAAAQwAB//8AAICA 
         AAAAAAAAAAEAAAAKAAAAAAoARwByAGUAZQBu"/> 
     </node> 
    </node> 
    <node data="AAAAAQAAAAEAAAAJAAAAQwAB//8AAP// 
       //8AAAAAAAEAAAAKAAAAAAgAQwB5AGEAbg=="> 
     <node data="AAAAAQAAAAEAAAAJAAAAQwAB/////6Wl 
        AAAAAAAAAAEAAAAKAAAAAAwATwByAGEAbgBnAGU="> 
      <node data="AAAAAQAAAAEAAAAJAAAAQwAB//8AAP// 
         //8AAAAAAAEAAAAKAAAAAAgAQwB5AGEAbg=="/> 
      <node data="AAAAAQAAAAEAAAAJAAAAQwAB//+AgAAA 
         gIAAAAAAAAEAAAAKAAAAAAwAUAB1AHIAcABsAGU="/> 
     </node> 
     <node data="AAAAAQAAAAEAAAAJAAAAQwAB//8AAICA 
        AAAAAAAAAAEAAAAKAAAAAAoARwByAGUAZQBu"> 
      <node data="AAAAAQAAAAEAAAAJAAAAQwAB//8AAAAA 
         //8AAAAAAAEAAAAKAAAAAAgAQgBsAHUAZQ=="/> 
      <node data="AAAAAQAAAAEAAAAJAAAAQwAB/////wAA 
         AAAAAAAAAAEAAAAKAAAAAAYAUgBlAGQ="/> 
     </node> 
    </node> 
</root> 
     """) 
    window.setGeometry(800, 300, 300, 300) 
    window.show() 
    sys.exit(app.exec_()) 
관련 문제