<p>你在这里要两样东西。</p>
<ol>
<li>您想要一个普通的python对象,<code>self.name</code>订阅<code>QLineEdit</code>上的更改。</li>
<li>您想让您的<code>QLineEdit</code>订阅普通python对象上的更改<code>self.name</code>。</li>
</ol>
<p>订阅<code>QLineEdit</code>上的更改很容易,因为这就是Qt信号/时隙系统的用途。你就是喜欢这样</p>
<pre><code>def __init__(self):
...
myQLineEdit.textChanged.connect(self.setName)
...
def setName(self, name):
self.name = name
</code></pre>
<p>更棘手的部分是让QLineEdit中的文本在<code>self.name</code>更改时更改。这很棘手,因为<code>self.name</code>只是一个普通的python对象。它对信号/插槽一无所知,而且python没有一个内置的系统,可以像C#那样观察对象的变化。但你仍然可以做你想做的事。</p>
<h2>使用带有Python属性特性的getter/setter</h2>
<p>最简单的事情就是把<code>self.name</code>变成<a href="http://docs.python.org/2/library/functions.html#property" rel="noreferrer">Property</a>。以下是链接文档中的一个简短示例(为了清楚起见,已修改)</p>
<pre><code>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
</code></pre>
<p>您可以添加一行来更新setter方法中的<code>QLineEdit</code>。这样,只要有任何东西修改了<code>x</code>的值,就会更新<code>QLineEdit</code>。例如</p>
<pre><code>@name.setter
def name(self, value):
self.myQLineEdit.setText(value)
self._name = value
</code></pre>
<p>注意,名称数据实际上被保存在名为<code>_name</code>的属性中,因为它必须与getter/setter的名称不同。</p>
<h2>使用真正的回调系统</h2>
<p>所有这些的缺点是,您不能在运行时轻松地更改这个观察者模式。要做到这一点,你需要一些真正像C提供的东西。python中的两个C风格的观察者系统是<a href="https://pypi.python.org/pypi/obsub/0.2" rel="noreferrer">obsub</a>和我自己的项目<a href="https://github.com/DanielSank/observed" rel="noreferrer">observed</a>。
我在自己的pyqt项目中使用了observated,并取得了很大的成功。
注意,PyPI上观察到的版本落后于github上的版本。我推荐github版本。</p>
<h2>创建自己的简单回调系统</h2>
<p>如果你想用最简单的方法自己做,你会做这样的事情</p>
<pre><code>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)
</code></pre>
<p>现在,如果您只是子类<code>Observed</code>,那么可以在运行时向任何方法添加回调。下面是一个简单的例子:</p>
<pre><code>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
</code></pre>
<p>现在,如果实现了如上所述的<code>.name</code>属性,就可以用<code>@event</code>装饰setter并订阅它。</p>