qtpropertiespyqtpyside

How to dynamically create Q_Properties


I want to create Q_Properties dynamically from a tuple containing the property names as strings.

The following non_dynamic code works:

class MyObject(QObject):
    def __init__(self,startval=42):
        self.ppval = startval

    def readPP(self):
        return self.ppval

    def setPP(self,val):
        self.ppval = val

    pp = QtCore.Property(int, readPP, setPP)

My first attempt was to use the setProperty function but it returns False, meaning the property is not added to the staticMetaObject and is therefore not visible to Qt's StyleSheets.

class MyObject(QWidget):
    def __init__(self,startval=42):
        self.ppval = startval
        print(self.setProperty('pp', QtCore.Property(int, self.readPP, self.setPP)))

    def readPP(self):
        return self.ppval

    def setPP(self,val):
        self.ppval = val

Another approach was to use setAttr. but again it fails to add the property to the staticMetaObject.

class MyObject(QWidget):
    def __init__(self,startval=42):
        self.ppval = startval
        setattr(self, 'pp', QtCore.Property(int, self.readPP, self.setPP)

    def readPP(self):
        return self.ppval

    def setPP(self,val):
        self.ppval = val

So far I haven't found a way to add something manually to staticMetaObject.


Solution

  • I'm going to stick my neck out here and say that I don't think it is possible to do this. The meta-object is created dynamically during the exceution of the python class statement, so it is not possible to add anything to it afterwards.

    You can try the following after the class is constructed:

        MyObject.pp = QtCore.Property(int, MyObject.readPP, MyObject.setPP)
    

    and it will function as a normal python property:

        obj = MyObject()
        print(obj.pp) # prints "42"
    

    but it will not be listed as a meta-property:

        meta = obj.metaObject()
        for index in range(meta.propertyCount()):
            print('meta: %s' % meta.property(index).name())
        # only prints "meta: objectName"
    

    The setProperty method is of no use here, because although it can be used to set the values of existing meta-properties, any new properties created in this way will not themselves become meta-properties. Instead, they will become dynamic properties, which can be read via qss but not set. Only meta-properties can be set via qss.

    So it looks like the only way to create meta-properties dynamically would be to create a new class using type. Instances of this new class could then be used as a proxy for gathering information from the stylesheet.