pygtk GtkTreeIter比较
我在PyGTK中有一个ListStore,里面有很多行数据。现在有一个后台任务在处理这些行代表的数据,当它处理完后,需要更新某一行。当然,为了更新某一行,它需要知道要更新的是哪一行,所以它会保存一个指向那一行的迭代器。不过,在后台任务运行的时候,用户可能会删除这行数据。这没问题——我们只需要把保存的迭代器替换成“None”,然后后台任务就可以继续运行了。问题是,当这一行被删除时,迭代器之间的比较结果并不相等,因此什么也不会被设置为None。实际上,据我所知,没有两个迭代器是可以比较相等的。问题在于一个简单的例子是这样的:
>>> store = gtk.ListStore(int)
>>> store.insert(1)
<GtkTreeIter at 0x1d49600>
>>> print store[0].iter == store[0].iter
False
结果是False,但它们其实是同一个迭代器!(我知道它们是不同的实例,但它们代表的是同样的东西,并且它们定义了一个__eq__
方法。) 我在这里漏掉了什么呢?我该如何在ListStore中跟踪行,以便后续更新呢?
2 个回答
我会用不同的方法来处理这个问题——这是我在类似情况下所做的:
- 每一行的数据对象其实是一个
GObject
的实例。 - 这个
GObject
的子类有很多属性。 - 当某个属性发生变化时,它会发出
notify::myproperty
的信号。
与此同时:
- 我的
ListStore
用来存储这些对象,并使用gtk.TreeViewColumn.set_cell_data_func()
方法来渲染每一列(下面有说明)。 - 对于每个对象/行,我管理
TreeView
的对象会连接到notify::myproperty
。 - 连接到这个
notify::...
信号的函数会触发ListStore
的row-changed
信号。
一些代码:
def on_myprop_changed(self, iter, prop):
path = self.model.get_path(iter)
self.model.row_changed(path ,iter)
def on_thing_processed(self, thingdata):
# Model is a ListStore
tree_iter = self.model.append((thingdata,))
# You might want to connect to many 'notify::...' signals here,
# or even have your underlying object emit a single signal when
# anything is updated.
hid = thingdata.connect_object('notify::myprop',
self.on_myprop_changed,
tree_iter)
self.hids.add((thingdata, hid))
我把隐藏的ID放在一个列表里,这样在清空表格时可以断开它们的连接。如果你让单独的行被移除,可能需要把它们存储在一个映射中(路径 -> hid,或者对象 -> hid)。
注意:你需要记住,set_cell_data_func
会在每次重绘时重新检查行的信息,所以底层的函数应该只是一个查找函数,而不是复杂的计算。实际上,由于这个原因,你可以不做“连接信号/发出行变化”的步骤,但我个人觉得这样做更好,因为这样可以避免一些特殊情况。
试试使用列表存储的 .get_path(iter)
方法,然后比较得到的路径,而不是直接比较迭代器。
更新:你可以直接用无效的 iter
调用 set_value
。虽然 gtk
会给你一个警告,但不会抛出异常或者其他什么。它可能只是检查一下这个迭代器是否有效。