You're asking for two different things here.
- You want to have a plain python object,
self.name
subscribe to changes on aQLineEdit
. - You want to have your
QLineEdit
subscribe to changes on a plain python objectself.name
.
Subscribing to changes on QLineEdit
is easy because that's what the Qt signal/slot system is for. You just do like this
def __init__(self):
...
myQLineEdit.textChanged.connect(self.setName)
...
def setName(self, name):
self.name = name
The trickier part is getting the text in the QLineEdit to change when self.name
changes. This is tricky because self.name
is just a plain python object. It doesn't know anything about signals/slots, and python does not have a built-in system for observing changes on objects in the way that C# does. You can still do what you want though.
Use a getter/setter with Python's property feature
The simplest thing to do is make self.name
a Property. Here's a brief example from the linked documentation (modified for clarity)
class Foo(object):
@property
def x(self):
"""This method runs whenever you try to access self.x"""
print("Getting self.x")
return self._x
@x.setter
def x(self, value):
"""This method runs whenever you try to set self.x"""
print("Setting self.x to %s"%(value,))
self._x = value
You could just add a line to update the QLineEdit
in the setter method. That way, whenever anything modifies the value of x
the QLineEdit
will be updated. For example
@name.setter
def name(self, value):
self.myQLineEdit.setText(value)
self._name = value
Note that the name data is actually being held in an attribute called _name
because it has to differ from the name of the getter/setter.
Use a real callback system
The weakness of all of this is that you can't easily change this observer pattern at run time. To do that you need something really like what C# offers. Two C# style observer systems in python are obsub and my own project observed. I use observed in my own pyqt projects with much success. Note that the version of observed on PyPI is behind the version on github. I recommend the github version.
Make your own simple callback system
If you want to do it yourself in the simplest possible way you would do something like this
import functools
def event(func):
"""Makes a method notify registered observers"""
def modified(obj, *arg, **kw):
func(obj, *arg, **kw)
obj._Observed__fireCallbacks(func.__name__, *arg, **kw)
functools.update_wrapper(modified, func)
return modified
class Observed(object):
"""Subclass me to respond to event decorated methods"""
def __init__(self):
self.__observers = {} #Method name -> observers
def addObserver(self, methodName, observer):
s = self.__observers.setdefault(methodName, set())
s.add(observer)
def __fireCallbacks(self, methodName, *arg, **kw):
if methodName in self.__observers:
for o in self.__observers[methodName]:
o(*arg, **kw)
Now if you just subclass Observed
you can add callbacks to any method you want at run time. Here's a simple example:
class Foo(Observed):
def __init__(self):
Observed.__init__(self)
@event
def somethingHappened(self, data):
print("Something happened with %s"%(data,))
def myCallback(data):
print("callback fired with %s"%(data,))
f = Foo()
f.addObserver('somethingHappened', myCallback)
f.somethingHappened('Hello, World')
>>> Something happened with Hello, World
>>> callback fired with Hello, World
Now if you implement the .name
property as described above, you can decorate the setter with @event
and subscribe to it.