4

我正在为 GTK3 程序创建一个插件。该插件可以在运行时启用或禁用。启用后,它应该在主机程序的给定区域(GtkBin)中填充其 GUI。禁用时,它应将自身从该区域中移除。

这个简单的程序描述了用法:

#!/usr/bin/python2

from gi.repository import Gtk

window = Gtk.Window()

class Plugin(object):
    def __init__(self, host):
        assert(isinstance(host, Gtk.Bin))
        self.host = host
        self.guest = None

    def enable(self):
        box = Gtk.Box(orientation = Gtk.Orientation.VERTICAL)
        for x in range(10):
            box.add(Gtk.Button("Button {}".format(x)))

        self.guest = box
        self.host.add(self.guest)

    def disable(self):
        self.host.remove(self.guest)
        # self.guest.destroy() # is this better?
        self.guest = None

plugin = Plugin(window)

plugin.enable()
#plugin.disable()

window.connect("destroy", Gtk.main_quit)
window.show_all()

Gtk.main()

我希望当插件被禁用时,它添加到主机的所有小部件都应该被正确处理。

我发现这个问题非常相似:GTK 中的 Free object/widget? 它提出gtk_container_removegtk_widget_destroy。但我很担心:

  1. 考虑gtk_container_remove。它删除了宿主容器的直接子容器。就我而言,孩子也是许多其他小部件的组合,它们可能相互引用。删除直接子元素是否足以处理所有小部件?

  2. 考虑gtk_widget_destroy。它是递归的,似乎是我需要的,但也似乎太残酷了。手动销毁小部件真的有必要吗?把这项工作留给参考柜台会更好吗?

我愿意听听这个案例的“最佳实践”。

4

2 回答 2

2

最佳实践是永远不要依赖垃圾收集器来及时收集控制有限资源的对象。它可能会无限期地延迟收集任何特定的垃圾。您不想让垃圾收集器清理一个文件,因为您一次可以打开的文件句柄的数量是有限的。

碰巧 Python 的垃圾收集器有一个引用计数器,并且会立即释放没有引用的对象,但这是一个实现细节。如果您使用其他实现,例如 PyPy 或 IronPython,则不适用。当我将它移到另一个实现时,我遇到了程序中断,因为我无意中依赖 Python 的引用计数来清理资源。此外,由于您不小心在某处创建了循环,您最终可能会遇到错误。

我不知道专门针对小部件的任何最佳实践。我没有考虑过我应该清理这些的可能性。如果一个小部件有一个与之关联的窗口,那就是理论上应该清理的操作系统句柄。通常,只有 GtkWindow 会有一个真正的窗口,但您的插件可以创建一个带有窗口的小部件。所以,我想说,在一种不太可能的特定情况下,理论上你应该销毁小部件。否则,如果您不需要它们,可以手动销毁它们,但我会说不要特意这样做。

于 2012-03-26T01:01:29.340 回答
1

从我的观点来看,你可以使用其中任何一个,因为会发生这样的事情:

  1. 当您使用gtk_container_remove时,如果您的子对象(self.guest)没有其他引用,那么它将自动销毁。我的意思是GtkContainer将减少引用计数,然后GObject系统将调用 gtk_widget_destroy。
  2. 如果您调用gtk_widget_destroy,那确实会销毁小部件,并且在此过程中将从其父级释放小部件。

所以,你可以使用其中任何一个,但我将使用第一个。

于 2012-03-26T13:32:46.630 回答