Currently There are a lot of attribute connection code need to manage.
I found a way in Qt System which can easy connect attribute with a simple mapping.
Utilize the Qt Meta Object System, we can find the property related changed signal automatically.
With this idea I developed a Data Binding Framework which much easier for multiple data sync value.
First of all, We can create a dynamic property in Qt Designer.
mgear_attr
describe what component attribute that it related.
Then we can read this attr in code and establish connection automatically.
class ConnectAttributeMixin(object):
PROPERTY_MAPPING = {
QtWidgets.QCheckBox: "checked",
QtWidgets.QSpinBox: "value",
QtWidgets.QDoubleSpinBox: "value",
QtWidgets.QComboBox: "currentIndex",
QtWidgets.QLineEdit: "text",
}
PROPERTY = "mgear_attr"
def connect_attributes(self, root):
# NOTES: iterate all QWidget
for widget in self.findChildren(QtWidgets.QWidget):
# NOTES: get custom property value
attr = widget.property(self.PROPERTY)
if not attr:
continue
# NOTES: get attribute from root
for cls,prop in self.PROPERTY_MAPPING.items():
if isinstance(widget,cls):
break
else:
continue
attr = root.attr(attr)
# NOTES: set attribute
widget.setProperty(prop, attr.get())
# NOTES: find the updater signal
meta = widget.metaObject()
index = meta.indexOfProperty(prop)
meta_prop = meta.property(index)
signal_name = meta_prop.notifySignal().name()
signal = getattr(widget, bytes(signal_name).decode())
# NOTES: connect signal to auto update value
signal.connect(lambda v=0, a=attr, p=prop, w=widget: a.set(w.property(p)))
class settingsTab(QtWidgets.QDialog, ConnectAttributeMixin, sui.Ui_Form):
"""The Component settings UI"""
def __init__(self, parent=None):
super(settingsTab, self).__init__(parent)
self.setupUi(self)
class componentSettings(MayaQWidgetDockableMixin, guide.componentMainSettings):
"""Create the component setting window"""
def __init__(self, parent=None):
self.toolName = GuideInfo.compType
# Delete old instances of the componet settings window.
pyqt.deleteInstances(self, MayaQDockWidget)
super(self.__class__, self).__init__(parent=parent)
self.settingsTab = settingsTab()
self.settingsTab.connect_attributes(self.root)
I create a ConnectAttributeMixin
class inherit by the settingsTab.
then just pass the self.root into connect_attributes
, then everything setup correctly.
Much easier to read and write.
Currently, this solution not support for QListWidget, More widget support can add to PROPERTY_MAPPING
constans variable.
How it work
PROPERTY_MAPPING
is mapping the Qt property, you can use QMetaObject to find what kind of the porperty inside the QObject.
widget = QtWidgets.QLineEdit()
meta = widget .metaObject()
for i in range(meta.propertyCount()):
prop = meta.property(i)
print(prop.name())
This code will print available property for a certain type of QObject.
Such as QLineEdit, we can find a property call text
.
Then alternatively, we can using setProperty
to modify the text value other than setText
.
widget = QtWidgets.QLineEdit()
widget.setProperty("text",'asd')
print(widget.text()) # widget.property("text") also get the same value
# asd
But the good things here, with the help of QMetaProperty, we can find the reletated notifySignal
and then setup the auto connection.