2014-12-01 123 views
2

我有一個簡化的代碼示例,其中一個窗口僅用一個按鈕創建。使用QTreeView編輯字典

enter image description here

按下它會彈出一個對話框的Qt其中TestDialog作爲需要參數Python字典。該字典顯示在對話框內的可編輯QTreeView中。

enter image description here

改變對您可以點擊一些值後取消接受或放棄更改。一旦對話框關閉,我的意圖是從主窗口中檢索修改後的字典dialog.get_data(),它現在只返回原始未修改的字典。點擊Ok按鈕後,檢索到的字典將打印到標準輸出。

我的問題是,如何修改樹視圖時修改字典?有沒有辦法自動附加一個函數來執行每個項目的修改?因此,在編輯時,例如,樹視圖中的float,那麼相應的值將更新爲字典中的浮點數?

字典沒有固定的大小,它的類型可能會改變。類型列表是有限的並且已知,並且對於該示例可以被縮減爲{intstr,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_()) 

回答

2

您可以連接到模型的itemChanged信號:

self.tree.model().itemChanged.connect(self.handleItemChanged) 

處理程序會是這個樣子:

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進行值的轉換不一定會出現k用於定製類,如Other。因此,您必須確保此類的構造函數可以轉換字符串表示形式,或者在將字符串傳遞給構造函數之前將其解析爲合適的參數。

另外請注意,我沒有打擾在上面的示例代碼中處理QString值。如果你使用Python 3,這不是問題,因爲它們默認會自動轉換爲Python字符串。在這個

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

有關詳細信息,請參閱Selecting Incompatible APIsPyQt4 Docs:但對於Python 2裏,你可以通過執行以下操作切換此行爲。