質問

TreeView / Model Madnessの2日後に終了したコードです。対象は私が思ったよりもはるかに広いように見えました。私は唯一の時間をそんなに費やすことができます歌のウィジェットを作成することができます。とにかく。 TreeView項目のドラッグアンドドロップ機能が有効になっています。しかし、興味深いプリントアウト以外にはあまりありません。アイテムをダブルクリックすると、ユーザーがピックアップされない新しいアイテム名を入力できます。

後で改訂されたコードで編集されました。

それは90%の機能ツールである。

ユーザは、ドラッグアンドドロップ、作成/複製/削除および名前変更によりツリービューアイテムを操作することができる。 TreeView項目は、「印刷」ボタンを押すことで(OS.makedirs()の代わりにドライブ上に作成される前に、ディレクトリまたはフォルダを階層的に表現しています(OS.Makedirs()ツールはまだ単に文字列として印刷します。
結果にかなり満足していると言うでしょう。 ハッキーデーと私の質問に答えた皆さんに感謝します。

最後の願い...

希望数01:

  1. 私はprintOut()メソッドがTreeViewアイテムをループするためによりエレガントなスマートな機能を使用して、make_dirs_from_dict()メソッドに渡されている辞書を構築することを望みます。
  2. ウィッシュ番号02:

    1. 私はアイテムを削除することがより安定しています。未知の理由によって、ツールが3番目/ 4回目の削除ボタンをクリックするとクラッシュします。これまでのところ、問題を解決できませんでした。
    2. 願い番号03: 3.みんなが最高のものであり、あなたの助けを感謝します:

      import sys, os
      from PyQt4 import QtGui, QtCore
      from PyQt4.QtGui import *
      from PyQt4.QtCore import *
      from copy import deepcopy
      import cPickle    
      
      class TreeItem(object):
          def __init__(self, name, parent=None):
      
              self.name = QtCore.QString(name)       
              self.parent = parent
              self.children = []       
              self.setParent(parent)
      
          def setParent(self, parent):
              if parent != None:
                  self.parent = parent
                  self.parent.appendChild(self)
              else:     self.parent = None
      
          def appendChild(self, child):
              self.children.append(child)
      
          def childAtRow(self, row):
              if len(self.children)>row: 
                  return self.children[row]
      
          def rowOfChild(self, child):       
              for i, item in enumerate(self.children):
                  if item == child:  return i
              return -1
      
          def removeChild(self, row):
              value = self.children[row]
              self.children.remove(value)
              return True
      
          def __len__(self):
              return len(self.children) 
      
      class TreeModel(QtCore.QAbstractItemModel):
          def __init__(self):
      
              QtCore.QAbstractItemModel.__init__(self)
      
              self.columns = 1
              self.clickedItem=None
      
              self.root = TreeItem('root', None) 
              levelA = TreeItem('levelA', self.root)
              levelB = TreeItem('levelB', levelA)
              levelC1 = TreeItem('levelC1', levelB)
              levelC2 = TreeItem('levelC2', levelB)
              levelC3 = TreeItem('levelC3', levelB)
              levelD = TreeItem('levelD', levelC3)
      
              levelE = TreeItem('levelE', levelD)
              levelF = TreeItem('levelF', levelE)
      
          def nodeFromIndex(self, index):
              return index.internalPointer() if index.isValid() else self.root
      
          def index(self, row, column, parent):        
              node = self.nodeFromIndex(parent)
              return self.createIndex(row, column, node.childAtRow(row))
      
          def parent(self, child):
              # print '\n parent(child)', child  # PyQt4.QtCore.QModelIndex
              if not child.isValid():  return QModelIndex()
              node = self.nodeFromIndex(child)       
              if node is None:   return QModelIndex()
              parent = node.parent           
              if parent is None:      return QModelIndex()       
              grandparent = parent.parent
      
              if grandparent==None:    return QModelIndex()
      
              row = grandparent.rowOfChild(parent)    
              assert row != - 1
      
              return self.createIndex(row, 0, parent)
      
          def rowCount(self, parent):
              node = self.nodeFromIndex(parent)
              if node is None: return 0
              return len(node)
      
          def columnCount(self, parent):
              return self.columns
      
          def data(self, index, role):
              if role == Qt.DecorationRole:
                  return QVariant()               
              if role == Qt.TextAlignmentRole:
                  return QVariant(int(Qt.AlignTop | Qt.AlignLeft))       
              if role != Qt.DisplayRole:   
                  return QVariant()                   
              node = self.nodeFromIndex(index)       
              if index.column() == 0:     
                  return QVariant(node.name)       
              elif index.column() == 1:   
                  return QVariant(node.state)       
              elif index.column() == 2:   
                  return QVariant(node.description)
              else:   return QVariant()
      
          def supportedDropActions(self):
              return Qt.CopyAction | Qt.MoveAction
      
          def flags(self, index):
              defaultFlags = QAbstractItemModel.flags(self, index)       
              if index.isValid():  return Qt.ItemIsEditable | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled | defaultFlags           
              else:   return Qt.ItemIsDropEnabled | defaultFlags  
      
          def setData(self, index, value, role):
              if role == Qt.EditRole:
                  if value.toString() and len(value.toString())>0: 
                      self.nodeFromIndex(index).name = value.toString()
                      self.dataChanged.emit(index, index)
                  return True
      
          def mimeTypes(self):
              return ['bstream', 'text/xml']
      
          def mimeData(self, indexes):
      
              mimedata = QtCore.QMimeData()
              bstream = cPickle.dumps(self.nodeFromIndex(indexes[0]))
              mimedata.setData('bstream', bstream)
              return mimedata
      
          def dropMimeData(self, mimedata, action, row, column, parentIndex):
      
              if action == Qt.IgnoreAction: return True  
      
              droppedNode=cPickle.loads(str(mimedata.data('bstream')))
      
              droppedIndex = self.createIndex(row, column, droppedNode)
      
              parentNode = self.nodeFromIndex(parentIndex)
      
              newNode = deepcopy(droppedNode)
              newNode.setParent(parentNode)
      
              self.insertRow(len(parentNode)-1, parentIndex)
      
              self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), parentIndex, parentIndex)
      
              return True
      
          def insertRow(self, row, parent):
              return self.insertRows(row, 1, parent)
          def insertRows(self, row, count, parent):
              self.beginInsertRows(parent, row, (row + (count - 1)))
              self.endInsertRows()
              return True
      
          def removeRow(self, row, parentIndex):
              return self.removeRows(row, 1, parentIndex)
      
          def removeRows(self, row, count, parentIndex):
              self.beginRemoveRows(parentIndex, row, row)
              node = self.nodeFromIndex(parentIndex)
              node.removeChild(row)
              self.endRemoveRows()       
              return True
      
      
      class GUI(QtGui.QDialog):
          def build(self, myWindow):
              myWindow.resize(600, 400)
              self.myWidget = QWidget(myWindow)        
              self.boxLayout = QtGui.QVBoxLayout(self.myWidget)
      
              self.treeView = QtGui.QTreeView()
      
              self.treeModel = TreeModel()
              self.treeView.setModel(self.treeModel)
              self.treeView.expandAll()
              self.treeView.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
              self.treeView.connect(self.treeView.model(), SIGNAL("dataChanged(QModelIndex,QModelIndex)"), self.onDataChanged)
              QtCore.QObject.connect(self.treeView, QtCore.SIGNAL("clicked (QModelIndex)"),  self.treeItemClicked)
              self.boxLayout.addWidget(self.treeView)
      
      
              self.PrintButton= QtGui.QPushButton("Print")  
              self.PrintButton.clicked.connect(self.PrintOut) 
              self.boxLayout.addWidget(self.PrintButton)
      
              self.DeleteButton= QtGui.QPushButton("Delete")  
              self.DeleteButton.clicked.connect(self.DeleteLevel) 
              self.boxLayout.addWidget(self.DeleteButton)
      
              self.insertButton= QtGui.QPushButton("Insert")  
              self.insertButton.clicked.connect(self.insertLevel) 
              self.boxLayout.addWidget(self.insertButton)
      
              self.duplicateButton= QtGui.QPushButton("Duplicate")  
              self.duplicateButton.clicked.connect(self.duplicateLevel) 
              self.boxLayout.addWidget(self.duplicateButton)
      
              myWindow.setCentralWidget(self.myWidget)
      
      
          def make_dirs_from_dict(self, dirDict, current_dir='/'):
              for key, val in dirDict.items():
                  #os.mkdir(os.path.join(current_dir, key))
                  print "\t\t Creating directory: ", os.path.join(current_dir, key)
                  if type(val) == dict:
                      self.make_dirs_from_dict(val, os.path.join(current_dir, key))
      
          def PrintOut(self):
              result_dict = {}
              for a1 in self.treeView.model().root.children:
                  result_dict[str(a1.name)]={}
                  for a2 in a1.children:
                      result_dict[str(a1.name)][str(a2.name)]={}
                      for a3 in a2.children:
                          result_dict[str(a1.name)][str(a2.name)][str(a3.name)]={}
                          for a4 in a3.children:
                              result_dict[ str(a1.name)][str(a2.name)][str(a3.name)][str(a4.name)]={}
                              for a5 in a4.children:
                                  result_dict[ str(a1.name)][str(a2.name)][str(a3.name)][str(a4.name)][str(a5.name)]={}
                                  for a6 in a5.children:
                                      result_dict[str(a1.name)][str(a2.name)][str(a3.name)][str(a4.name)][str(a5.name)][str(a6.name)]={}
                                      for a7 in a6.children:
                                          result_dict[str(a1.name)][str(a2.name)][str(a3.name)][str(a4.name)][str(a5.name)][str(a6.name)][str(a7.name)]={}
      
      
              self.make_dirs_from_dict(result_dict)                      
      
      
          def DeleteLevel(self):
              if len(self.treeView.selectedIndexes())==0: return
      
              currentIndex = self.treeView.selectedIndexes()[0]
              currentRow=currentIndex.row()
              currentColumn=currentIndex.column()
              currentNode = currentIndex.internalPointer()
      
              parentNode = currentNode.parent
              parentIndex = self.treeView.model().createIndex(currentRow, currentColumn, parentNode)
              print '\n\t\t\t CurrentNode:', currentNode.name, ', ParentNode:', currentNode.parent.name, ', currentColumn:', currentColumn, ', currentRow:', currentRow 
      
              # self.treeView.model().removeRow(len(parentNode)-1, parentIndex) 
      
              self.treeView.model().removeRows(currentRow, 1, parentIndex )
      
              #self.treeView.model().removeRow(len(parentNode), parentIndex)
              #self.treeView.model().emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), parentIndex, parentIndex) 
      
          def insertLevel(self):
              if len(self.treeView.selectedIndexes())==0: return
      
              currentIndex = self.treeView.selectedIndexes()[0]
              currentNode = currentIndex.internalPointer()
              newItem = TreeItem('Brand New', currentNode)
              self.treeView.model().insertRow(len(currentNode)-1, currentIndex)
              self.treeView.model().emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), currentIndex, currentIndex)   
      
          def duplicateLevel(self):
              if len(self.treeView.selectedIndexes())==0: return
      
              currentIndex = self.treeView.selectedIndexes()[0]
              currentRow=currentIndex.row()
              currentColumn=currentIndex.column()
              currentNode=currentIndex.internalPointer()
      
              parentNode=currentNode.parent
              parentIndex=self.treeView.model().createIndex(currentRow, currentColumn, parentNode)
              parentRow=parentIndex.row()
              parentColumn=parentIndex.column()
      
              newNode = deepcopy(currentNode)
              newNode.setParent(parentNode)
      
              self.treeView.model().insertRow(len(parentNode)-1, parentIndex)
              self.treeView.model().emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), parentIndex, parentIndex) 
      
              print '\n\t\t\t CurrentNode:', currentNode.name, ', ParentNode:', parentNode.name, ', currentColumn:', currentColumn, ', currentRow:', currentRow, ', parentColumn:', parentColumn, ', parentRow:', parentRow 
              self.treeView.update()
              self.treeView.expandAll()
      
      
          def treeItemClicked(self, index):
              print "\n clicked item ----------->", index.internalPointer().name
      
          def onDataChanged(self, indexA, indexB):
              print "\n onDataChanged NEVER TRIGGERED! ####################### \n ", index.internalPointer().name
              self.treeView.update(indexA)
              self.treeView.expandAll()
              self.treeView.expanded()
      
      
      
      if __name__ == '__main__':
      
          app = QtGui.QApplication(sys.argv)
      
          myWindow = QMainWindow()
          myGui = GUI()
          myGui.build(myWindow)
          myWindow.show()
          sys.exit(app.exec_())
      
      .

役に立ちましたか?

解決

あなたが達成しようとしていることを完全に確信していませんが、ドロップ操作でドラッグしたアイテムを取得したいように聞こえ、ダブルクリックして新しいノード名を保存してください。

最初に、ドラッグした項目をmimeDataに保存する必要があります。現在、あなたは「Mimedata」という文字列を保存しています。 mimeType 文字列(ここでは、私は 'bstream'を使用した ')を実際には何でもすることができます。データを取得するために使用するものと一致する限り、モデルのmimeTypesメソッドによって返されるリストにあります。オブジェクト自体を渡すには、まずそれをシリアル化する必要があります(オブジェクトを実行しているものがある場合はXMLに変換することもできます)。

のための標準タイプではありません。

保存するデータを保存するには、モデルのSetDataメソッドを再実装し、EditRoleの動作を定義する必要があります。

関連方法:

def setData(self, index, value, role):
    if role == Qt.EditRole:
        self.nodeFromIndex(index).name = value
        self.dataChanged.emit(index, index)
        return True

def mimeTypes(self):
    return ['bstream', 'text/xml']

def mimeData(self, indexes):
    mimedata = QtCore.QMimeData()
    # assuming single dragged item ...
    # only pass the node name
    # mimedata.setData('text/xml', str(self.nodeFromIndex(indexes[0]).name))
    # pass the entire object
    bstream = cPickle.dumps(self.nodeFromIndex(indexes[0]))
    mimedata.setData('bstream', bstream)
    return mimedata

def dropMimeData(self, mimedata, action, row, column, parentIndex):

    if action == Qt.IgnoreAction: return True        

    parentNode = self.nodeFromIndex(parentIndex)

    # data = mimedata.data('text/xml')
    data = cPickle.loads(str(mimedata.data('bstream')))
    print '\n\t incoming row number:', row, ', incoming column:', column, \
        ', action:', action, ' mimedata: ', data.name

    print "\n\t Item's name on which drop occurred: ", parentNode.name, \
        ', number of its childred:', len(parentNode.children)

    if len(parentNode.children)>0: print '\n\t zero indexed child:', parentNode.children[0].name

    return True
.

編集:
それはあなたが更新したコードがたくさんありますが、私はあなたが強調したポイントを義務付けます。モデルクラスの外部でcreateIndexを呼び出しないようにします。これはQTの保護された方法です。 Pythonはプライベート/プロテクト変数またはメソッドを強制しませんが、他の言語からライブラリを使用するときは、そのクラスの意図された組織を尊重し、それらにアクセスします。

モデルの目的はあなたのデータへのインターフェースを提供することです。 indexdataparentなどを使用してアクセスする必要があります。特定のインデックスの親を取得するには、そのインデックス(またはモデルの)parent関数を使用します。これはQModelIndexも返します。このようにして、データの内部構造を通過する(または確かに知っている)必要はありません。これはdeleteLevelメソッドで行ったことです。

からQt docs

データの表現がアクセスされる方法とは別に保持されるようにするために、モデルインデックスの概念が導入されます。モデルを介して取得できる各情報はモデルインデックスで表されます。モデルのみを知る必要があり、モデルによって管理されるデータの種類は一般的に定義できます。

また、再帰を使用して印刷方法を簡素化できます。

def printOut(self):
    result_dict = dictify(self.treeView.model().root)
    self.make_dirs_from_dict(result_dict)  

def deleteLevel(self):
    if len(self.treeView.selectedIndexes()) == 0: 
        return

    currentIndex = self.treeView.selectedIndexes()[0]
    self.treeView.model().removeRow(currentIndex.row(), currentIndex.parent())
.

私はクラス

とは別に別々でした
def dictify(node):
    kids = {}
    for child in node.children:
        kids.update(dictify(child)) 
    return {str(node.name): kids}
.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top