pygtk GtkTreeIter 比较

发布于 2024-11-08 17:25:44 字数 541 浏览 2 评论 0原文

我在 PyGTK 中有一个 ListStore,其中有很多行。有一个后台作业正在处理行所表示的数据,当它完成时,它需要更新该行。当然,要做到这一点,它需要知道要更新哪一行,从而保持该行的迭代器。但是,在后台作业生命周期中,用户可能会删除该行。这没关系——我们只需将存储的迭代器替换为“None”,后台作业就可以愉快地继续进行。问题是,当删除该行时,迭代器比较不相等,并且没有任何内容设置为 None。事实上,据我所知,没有两个迭代器比较相等。在一个最小的例子中,问题是这样的:

>>> store = gtk.ListStore(int)
>>> store.insert(1)
<GtkTreeIter at 0x1d49600>
>>> print store[0].iter == store[0].iter
False

错误,但它们是相同的迭代器! (我知道它们是不同的实例,但它们代表相同的事物,并且它们定义了一个 __eq__ 方法。)我在这里缺少什么,以及如何跟踪 ListStore 中的行以后更新?

I have a ListStore in PyGTK, which has a bunch of rows. There is a background job processing the data represented by the rows, and when it finishes, it needs to update the row. Of course, to do this, it needs to know which row to update, and is thus keeping an iterator to the row around. However, during the background jobs life, the user might remove the row. This is OK — we just replace the stored iterator with "None", and the background job continues along merrily. The problem is that when the row is removed, the iterators don't compare as equal, and nothing gets set to None. In fact, no two iterators, AFAIK, compare equal. The problem, in a minimal example, is this:

>>> store = gtk.ListStore(int)
>>> store.insert(1)
<GtkTreeIter at 0x1d49600>
>>> print store[0].iter == store[0].iter
False

False, yet they're the same iterator! (I'm aware they are different instances, but they represent the same thing, and they define a __eq__ method.) What am I missing here, and how do I keep track of rows in a ListStore for later updating?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

[浮城] 2024-11-15 17:25:44

尝试使用列表存储的 .get_path(iter) 方法,并比较结果路径,而不是直接比较迭代器。

更新:您只需使用无效的 iter 调用 set_value 即可。 gtk 会给你一个警告,但不会抛出异常或任何东西。它可能只是检查它是否是一个有效的 iter。

Try using the list store's .get_path(iter) method, and compare the resulting paths, instead of comparing the iterators directly.

UPDATE: You can just call set_value with the invalid iter. gtk will give you a warning but will not throw an exception or anything. It probably just checks whether it's a valid iter anyway.

水水月牙 2024-11-15 17:25:44

我会以不同的方式处理这个问题 - 这是我在类似情况下所做的:

  1. 每行中表示的基础数据对象是 GObject 的实例
  2. 这个 GObject 子类有一个一堆属性
  3. 当属性发生变化时,它会发出 notify::myproperty 信号

同时:

  1. 我的 ListStore 存储这些对象,并使用 gtk.TreeViewColumn .set_cell_data_func() 方法渲染每列(参见下面的注释)
  2. 对于每个对象/行,管理 TreeView 的对象连接到 notify::myproperty
  3. 连接到此 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))

我将 hids 保留在一个列表,以便我可以在表格被清除时断开它们的连接。如果您让个别行被删除,您可能需要将它们存储在地图中(路径 -> hid,或对象 -> hid)。

注意:您需要记住,set_cell_data_func 会导致该行在每次重绘时重新检查其信息,因此底层函数应该只是一个查找函数,而不是一个密集计算。实际上,因此您可以不执行“连接到信号/发出行更改”过程,但我个人感觉更好,因为知道不会有任何边缘情况。

I would approach this differently — here's what I've done in a similar situation:

  1. The underlying data object represented in each row is an instance of a GObject
  2. This GObject subclass has a bunch of properties
  3. When the property changes, it emits the notify::myproperty signal

At the same time:

  1. My ListStore stores these objects, and uses the gtk.TreeViewColumn.set_cell_data_func() method to render each column (see note below)
  2. For each object/row, my object managing the TreeView connects to the notify::myproperty
  3. The function connected to this notify::... signal triggers the row-changed signal on the ListStore

Some code:

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))

I keep the hids in a list so I can disconnect them when the table is cleared. If you let individual rows get removed, you'll probably need to store them in a map (path -> hid, or object -> hid).

Note: You need to remember that set_cell_data_func causes the row to re-check its information every time there's a redraw, so the underlying function should just be a lookup function, not an intensive computation. Practically speaking, because of this you could get away with not doing the "connect-to-signal/emit-row-changed" procedure, but personally I feel better knowing that there won't be any edge cases.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文