简体   繁体   中英

How to dispose GtkWidget's in Python, GTK3 and PyGObject?

I am creating a plug-in to a GTK3 program. This plug-in can be enabled or disabled at runtime. When enabled, it should populate its GUI in a given area (a GtkBin) in the host program. When disabled, it should remove itself from that area.

This simple program depicts the usage:

#!/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()

I wish that when the plug-in is disabled, all widgets it added to the host should be properly disposed.

I have found this question quite similar: Free object/widget in GTK? It proposed gtk_container_remove and gtk_widget_destroy . But I am worrying:

  1. Consider gtk_container_remove . It removes the direct child of the host container. In my case, the child is also a composition of many other widgets and they may be referencing each other. Will removing the direct child enough for all the widgets to be disposed?

  2. Consider gtk_widget_destroy . It is recursive and appears to be what I need, but also seems too brutal. Is this really necessary to manually destroy a widget? Would it be better to leave that job to the reference-counter?

I am willing to hear the "best practice" for this case.

Best practice is to never rely on a garbage collector to collect an object that controls a limited resource in a timely fashion. It could delay collecting any particular garbage indefinitely. You wouldn't want to leave a file open for the garbage collector to clean up, because there's a limit to the number of file handles you can have open at once.

It happens that Python's garbage collector has a reference counter and will free objects with no references immediately, but that is an implementation detail. If you use another implementation, such as PyPy or IronPython, this does not apply. I've had a program break when I moved it to another implementation, because I had inadvertently relied on Python's reference counting to clean up resources. Also, you can end up with bugs that happen because you accidentally create a cycle somewhere.

I don't know of any best practices for widgets specifically. I hadn't considered the possibility that I should be cleaning those up. If a widget has a window associated with it, that is an OS handle that you should theoretically clean up. Usually, only a GtkWindow will have a real window, but it's possible for your plugin to create a widget with a window. So, I would say that in that one specific unlikely case, you should theoretically destroy the widget. Otherwise, it's fine to destroy them manually if you don't need them, but I would say don't go out of your way to do so.

From my point you can use any of those, since what will happens is this:

  1. When you use gtk_container_remove , if your child object (self.guest) have no other reference, then it will be destroyed automatically. I mean GtkContainer will decrease the reference count and the GObject system will call then gtk_widget_destroy.
  2. If you call gtk_widget_destroy , the that will indeed destroy the widget, and in the process will release the widget from its parent.

So, you can use any of those, but I will use the first one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM