سؤال

أحاول كتابة محرر عقارات بسيط. لقد قمت تلقائيًا بإنشاء فئة PYQT (WorkZone في الكود أدناه) ، وأحتاج إلى عرض/تحرير بعض خصائصها مع Propertyeditor ، مع PropertyedIditorDeleGate ، التي تستخدم محررين مخصصين Coloreditor ، Lineeditor ، إلخ.

الفكرة الرئيسية هي أن WorkZone يعرف ما هي الخصائص التي يجب تحريرها وكيف ، و Propertyeditor Parse WorkZone ، تبحث عن مثل هذه الخصائص ، وملء QtreewIdget مع قيمها.

ولكن هناك مشكلة: لا يبدأ Depate في التحرير عند النقر المزدوج ، أو "أدخل" ، أو SMTH. يضاف إلى الصف الأيمن ، فهو يرسم العنصر ، ولكن هذا كل شيء. بالإضافة إلى ذلك ، عندما قمت بتبديل نوع حاوية PropertyEditor إلى QTableWidget ، بدأ Depatate في العمل بشكل أكثر ملاءمة (ولكن المحرر رسم في زاوية الشاشة ، وليس في الجدول)!

ملاحظة. وسؤال إضافي واحد: هل هناك أي طريقة لإضافة بعض المندوبين إلى صفوف دون الحاجة إلى تخزين مثيلاتهم في مكان آخر (Self._delegates في البرنامج النصي) ، إنه مجرد قبيح. Method 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_())
هل كانت مفيدة؟

المحلول

انتهى بي الأمر إلى التعامل مع النقر المزدوج لتعيينه على قابلة للتحرير ، وإجبار العنصر على تعديل وضع التحرير باستخدام 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 الأولى فقط إلى العمل ، ولكن هذا شعر صحيح.

نصائح أخرى

على PS.

من توثيق PYQT

qabstractitemview.setItemDelegate (Self ، QabstractItemDelegate)

يعين مندوب العنصر لهذا العرض ونموذجه للتفويض. هذا مفيد إذا كنت تريد التحكم الكامل في تحرير وعرض العناصر.

سيتم إزالة أي مندوب حالي ، ولكن لا يتم حذفه. QabstractItemView لا يأخذ ملكية المندوب.

تحذير: يجب ألا تشارك نفس مثيل المندوب بين وجهات النظر. يمكن أن يتسبب القيام بذلك في سلوك التحرير غير الصحيح أو غير البديهي لأن كل طريقة عرض متصلة بمندوب معين قد يتلقى إشارة المحول المقرز () ، ومحاولة الوصول إلى محرر أو إغلاقه تم إغلاقه بالفعل.

الإجابة بسيطة ، كما هو الحال دائمًا .. ٪) لا تتضمن الأعلام الافتراضية لـ QTreewIdgetItem

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top