2010-03-04 181 views
-1

我正在尝试编写简单的属性编辑器。我已经自动生成pyqt类(WorkZone在下面的代码中),我需要使用PropertyEditor查看/编辑它的一些属性,并使用代表PropertyEditorDelegate,它使用自定义编辑器ColorEditor,LineEditor等。PyQt自定义代理QTreeWidget问题

主要思想是WorkZone知道需要编辑哪些属性以及如何编辑属性,PropertyEditor解析WorkZone,寻找这样的属性,并填充QTreeWidget及其值。

但有一个问题:委托没有开始编辑双击,或'输入',或smth。它被添加到正确的行,它绘制的项目,但就是这样。 此外,当我将Propertyeditor容器的类型切换到QTableWidget时,委托开始工作得更加正确(但编辑器画在屏幕的角落,而不是表格中)!

PS。还有一个问题:是否有任何方法可以将某些委托添加到行中,而无需将其实例存储在其他位置(self._delegates在脚本中),这只是丑陋的。方法setItemDelegate接受指向委托的指针,并且在C++中获得所有权,但在PyQT中并不是这样......除此之外,例如,setItem没有这样的问题。

下面的脚本说明了这个问题:

# -*- coding: utf-8 -*- 
#!/usr/bin/env python 

from PyQt4 import QtCore, QtGui 
import inspect 


class LineEditor(QtGui.QLineEdit): 


    def __init__(self, name = None, parent = None, slot = None): 
     QtGui.QLineEdit.__init__(self, parent) 
     self.textChanged.connect(slot) 
     self.name = name 

    @staticmethod 
    def paintForDelegate(delegate, painter, option, index): 
     QtGui.QItemDelegate.paint(delegate, painter, option, index) 

    def get(self): 
     return str(self.text()) 

    def set(self, val): 
     self.setText(QtCore.QString.fromUtf8(val)) 

class ColorEditor(QtGui.QComboBox): 


    def _populateList(self): 
     for name in QtGui.QColor.colorNames(): 
      self.addItem(name) 
      index = self.findText(name) 
      self.setItemData(index, QtGui.QColor(name), QtCore.Qt.DecorationRole) 

    def __init__(self, name = None, parent = None, slot = None): 
     QtGui.QComboBox.__init__(self, parent) 
     self._populateList() 
     self.currentIndexChanged.connect(slot) 
     self.name = QtCore.QString.fromUtf8(name) 

    @staticmethod 
    def paintForDelegate(delegate, painter, option, index): 
     QtGui.QItemDelegate.paint(delegate, painter, option, index) 

    def get(self): 
     qColor = QtGui.QColor(self.itemData(self.currentIndex(), QtCore.Qt.DecorationRole))   
     color = ((qColor.blue() | (qColor.green() << 8)) | (qColor.red() << 16)) 
     return color 

    def set(self, val): 
     blue = (val & 255) 
     green = ((val & 65280) >> 8) 
     red = ((val & 16711680) >> 16) 
     color = QtGui.QColor(red, green, blue) 
     index = self.findData(color, QtCore.Qt.DecorationRole) 
     self.setCurrentIndex(index) 

class PropertyEditorDelegate(QtGui.QItemDelegate): 


    def __init__(self, object, propName, parent = None): 
     QtGui.QItemDelegate.__init__(self, parent) 
     self._object = object 
     self._propName = propName 

    def paint(self, painter, option, index): 
     self._object.paintForDelegate(self._propName, self, painter, option, index) 

    def createEditor(self, parent, option, index): 
     return self._object.createEditor(self._propName) 

    def setEditorData(self, editor, index): 
     value = index.model().data(index, QtCore.Qt.EditRole) 
     editor.set(value) 

    def setModelData(self, editor, model, index): 
     if index.column() == 0: 
      model.setData(index, editor.name, QtCore.Qt.EditRole) 
     else: 
      model.setData(index, editor.get(), QtCore.Qt.EditRole) 

    def updateEditorGeometry(self, editor, option, index): 
     editor.setGeometry(option.rect) 

class PropertyEditor(QtGui.QWidget): 

    def __init__(self, parent = None): 
     QtGui.QWidget.__init__(self, parent) 
     self._object = None 
     self._delegates = [] 
     self._mainLayout = QtGui.QVBoxLayout() 
     self._mainLayout.setContentsMargins(2, 2, 2, 2) 
     self._mainLayout.setSpacing(2) 
     self.setLayout(self._mainLayout) 
     self._contents = QtGui.QTreeWidget() 
     self._contents.setColumnCount(2) 
     self._contents.currentItemChanged.connect(self.printCurrent) 
     self._mainLayout.addWidget(self._contents) 

    def printCurrent(self, curr, prev): 
     print self._contents.currentIndex().row() 
     print self._contents.currentIndex().column() 
     print self._contents.itemDelegate(self._contents.currentIndex())._propName 
     print self._contents.itemDelegate(self._contents.currentIndex()) 

    def object(self): 
     return self._object 

    def setObject(self, value):  
     self._object = value 

     def isProperty(p): 
      return isinstance(p, property) 

     for (name, value) in inspect.getmembers(type(self._object), isProperty): 
      if self._object.isEditable(name): 
       item = QtGui.QTreeWidgetItem() 
       item.setData(0, QtCore.Qt.EditRole, QtCore.QString.fromUtf8(self._object.getPropertyName(name))) 
       item.setData(1, QtCore.Qt.EditRole, self._object.get(name)) 
       self._contents.addTopLevelItem(item) 

       self._delegates.append(PropertyEditorDelegate(self._object, name, self._contents)) 
       index = self._contents.indexOfTopLevelItem(item)  
       self._contents.setItemDelegateForRow(index, self._delegates[index]) 

class WorkZone(object): 


    def __init__(self): 

     self._name = '' 
     self.currentEditor = None 
     self.red = 100 
     self.green = 100 
     self.blue = 100 
     self._width = 1 

    def _getColor(self): 
     color = ((self.blue | (self.green << 8)) | (self.red << 16)) 
     return color 

    def _setColor(self, color): 
     self.blue = (color & 255) 
     self.green = ((color & 65280) >> 8) 
     self.red = ((color & 16711680) >> 16) 

    color = property(_getColor, _setColor) 

    def currentColorChanged(self, index): 
     if self.currentEditor is not None: 
      self.color = self.currentEditor.get() 
     print self.color 

    def currentNameChanged(self, newName): 
     if self.currentEditor is not None: 
      self.name = self.currentEditor.get() 
     print self.name 

    def createEditor(self, prop): 
     if prop == 'color': 
      self.currentEditor = ColorEditor('Color', None, self.currentColorChanged) 
      self.currentEditor.set(self.color) 
      return self.currentEditor 
     elif prop == 'name': 
      self.currentEditor = LineEditor('Name', None, self.currentNameChanged) 
      self.currentEditor.set(self.name) 
      return self.currentEditor 
     else: 
      return None 

    def releaseEditor(self): 
     self.currentEditor = None 

    def isEditable(self, prop): 
     if prop == 'color': 
      return True 
     elif prop == 'name': 
      return True 
     else: 
      return False 

    def set(self, prop, val): 
     if prop == 'color': 
      self.color = val 
     elif prop == 'name': 
      self.name = val 

    def get(self, prop): 
     if prop == 'color': 
      return self.color 
     elif prop == 'name': 
      return self.name 

    def getPropertyName(self, prop): 
     if prop == 'color': 
      return 'Color' 
     elif prop == 'name': 
      return 'Name' 

    def paintForDelegate(self, prop, delegate, painter, option, index): 
     if prop == 'color': 
      ColorEditor.paintForDelegate(delegate, painter, option, index) 
     elif prop == 'name': 
      LineEditor.paintForDelegate(delegate, painter, option, index) 

    def _setWidth(self, Width): 
     self._width = Width 

    def _getWidth(self): 
     return self._width 

    width = property(_getWidth, _setWidth) 

    def _getName(self): 
     return self._name 

    def _setName(self, val): 
     self._name = val 

    name = property(_getName, _setName) 



if __name__ == '__main__': 

    import sys 

    app = QtGui.QApplication(sys.argv) 
    zone = WorkZone() 
    zone.color = 0 
    zone.width = 1 
    propertyEditor = PropertyEditor() 
    propertyEditor.setObject(zone) 


    propertyEditor.show() 
    sys.exit(app.exec_()) 

回答

2

我结束了处理双击设置为可编辑,强制项目编辑模式与editItem(),然后将其设置回来。代表本身处理所有的显示和编辑。

# In __init__: 
    self.tree.itemActivated.connect(self.onDoubleClick) 


def onDoubleClick(self, item, index): 
    """ 
    The logic will happen in the editor delegate. This is needed to let 
    the delegate run by making this editable 
    """   
    item.setFlags(QtCore.Qt.ItemIsSelectable | 
        QtCore.Qt.ItemIsEnabled | 
        QtCore.Qt.ItemIsEditable)    

    # Force the item in to edit mode so the delegate picks it up 
    self.tree.editItem(item, index) 

    # Set the item back to not editable. The delegate will still do its 
    # job, but the read-only state will already be set when done! 
    item.setFlags(QtCore.Qt.ItemIsSelectable | 
        QtCore.Qt.ItemIsEnabled) 

第一个setFlags可能只需要ItemIsEditable工作,但这种感觉是对的。

0

答案很简单,一如既往。对于QTreeWidgetItem%) 默认标志不包括QtCore.Qt.ItemIsEditable。

1

On PS。

从PyQt的

QAbstractItemView.setItemDelegate的文档(个体经营,QAbstractItemDelegate)

设置此视图和模型委托的项目委托。如果您想完全控制项目的编辑和显示,这非常有用。

任何现有的委托将被删除,但不会被删除。 QAbstractItemView不承担委托代理的所有权。

警告:您不应在视图之间共享委托的同一个实例。这样做会导致不正确或不直观的编辑行为,因为连接到给定委托的每个视图都可能会收到closeEditor()信号,并尝试访问,修改或关闭已关闭的编辑器。