I want to bind some QWidgets to the attributes of an existing class in Python 3 so that any changes made through the GUI are applied to the underlying data objects in a clean and simple fashion.
My existing class looks like this (simplified):
class Player:
def __init__(self):
self._health = 100
@property
def health(self):
return self._health
@health.setter
def health(self, value):
self._health = value
PyQt5 allows connecting Qt signals to any method, so I can easily achieve my goal by calling someWidget.valueChanged.connect(player.someSetterMethod)
.
However, I use @property
and thus, the setter name is identical to the attribute name. When I try using player.health
, it is interpreted as an integer (as expected, but obviously not what I want here).
I am aware that I could define getter/setter methods with custom names and then use property()
instead of @property
, but I am hoping there is a way of obtaining the reference to the setter method so that I can pass it to connect()
.
Thank you!
Edit: I doubt it is relevant to this question, but perhaps I should add that in the next step, I want to report changes that are not applied as received back to the GUI.
You'll have to use a lambda
, because you need a bound property to get the right context:
someWidget.valueChanged.connect(lambda v: setattr(player, 'health', v))
Property objects do have .fget
and .fset
attributes, and the property object itself can be accessed on the class:
Player.health.fset
Player.health.fget
but these give you access to the original unbound function objects, which require the self
parameter still.
You could use those functions too, but then you'd have to bind them to your instance first:
someWidget.valueChanged.connect(Player.health.fset.__get__(player))
The __get__
method on the function (which is a descriptor ) to provide you with a bound method which passes in the self
argument for you (the player
instance object in this case).
As seen here https://docs.python.org/3/library/functions.html#property
The returned property object also has the attributes fget, fset, and fdel corresponding to the constructor arguments
So you can access the getter, setter and deleter via these attributes. In your example Player.health.fset(some_instance, new_health)
In order to connect that to your signal you must bind the instance to the setter. This can be done with functools.partial
from functools import partial
someWidget.valueChanged.connect(partial(Player.health.fset, player))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.