问题
Currently I'm using PyQT, which I very much like so far. However, I need to have two-way bindings and from the sparse information I could find on the internet this is the way to do it. Create a PyQTProperty, attach a getter, a setter and a signal (which must be called whenever the value has changed in order to notify the GUI).
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject
class Test(QObject):
signal = pyqtSignal()
def getName(self):
print("name gotten")
return self._name
def setName(self, name):
print("name changed to " + name)
self.signal.emit()
self._name = name
name = pyqtProperty('QString', fget= getName, fset= setName, notify= signal)
def __init__(self, parent=None):
super().__init__(parent)
# Initialise the value of the properties.
self._name = 'asdf'
This works as expected. However, I'm not sure if I'm indeed using it correctly, but this looks absolutely horrible to me. In fact, it smells so bad that I'm inclined to open a window. Instead of being able to simply declare an attribute, I now have to create a setter and a getter (before the declaration even, meaning there will be declarations halfway through the source file) and a signal for each attribute. This leads to a lot of duplicate code, and unreadable source files.
What would be the best way to change this to one or two lines? For example through automatic code generation, metaprogramming or macros (I've looked into MacroPy, but was not sure if this would be the way to go). So something like this:
name = # magic Python voodoo, automatically handling setters, getters and the signal
Thanks in advance, and please let me know if I need to supply additional information.
Edit: Thanks to BrenBarn I noticed I forgot to mention how this code is actually called upon. The GUI is implemented in QML (Qt Markup Language), and this object is made known to QML by registering it (like here, qmlRegisterType), after which QML can instantiate and manipulate instances of it. I decided not to include the full source code example for brevity, and because I'm mainly interested in a better way of handling the getter/setter and the instantiating of the signal, without focusing on QML.
回答1:
You can use a pyqtProperty() decorator as mentioned in the documentation. It does at least remove the separate definition.
signal = pyqtSignal
@name.setter
def name(self, name):
self._name = name
self.signal.emit()
@pyqtProperty('QString', notifiy=signal)
def name(self):
return self._name
来源:https://stackoverflow.com/questions/44335782/better-way-to-handle-two-way-binding-in-pyqt