Better way to handle two-way binding in PyQt?

爷,独闯天下 提交于 2019-12-01 07:11:59

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!