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

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:
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?
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:
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.
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.

Related

Proper way of building Gtk3 applications in Python

I have just started learning about creating GUI apps in Python. I decided to use Gtk version 3.
According to the (official?) tutorial on http://python-gtk-3-tutorial.readthedocs.org/ the proper way of building a hello world application is:
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.set_default_size(200, 100)
self.connect('destroy', Gtk.main_quit)
self.show_all()
MyWindow()
Gtk.main()
In other tutorial (http://www.micahcarrick.com/gtk3-python-hello-world.html) I found completly different aproach which is:
from gi.repository import Gtk, Gio
class HelloWorldApp(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self, application_id="apps.test.helloworld",
flags=Gio.ApplicationFlags.FLAGS_NONE)
self.connect("activate", self.on_activate)
def on_activate(self, data=None):
window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL)
window.set_title("Gtk3 Python Example")
window.set_border_width(24)
label = Gtk.Label("Hello World!")
window.add(label)
window.show_all()
self.add_window(window)
if __name__ == "__main__":
app = HelloWorldApp()
app.run(None)
Could someone experienced in this category tell me in what way should I write Gtk 3 apps in python these days? I'm already familiar with writing GUIs (spent few months in Java's Swing) so you can go on with terms like events, callbacks and so on..
Choosing to write your new program with a GtkApplication or just a GtkWindow depends on the functionality you require, and to some extent the intended audience.
For most cases, especially when you are still learning the toolkit, I would tend to agree with valmynd that GtkApplication is unnecessarily complicated. GtkApplication provides a lot of extra functionality that you probably don't want or need in smaller applications.
For larger, more complete applications I agree with Dragnucs, the second approach is superior and can provide better integration into the desktop environment. From GNOME Goal: Port to GtkApplication (see also the GtkApplication docs):
Porting your application to use GtkApplication has quite nice benefits:
GtkApplication handles GTK+ initialization, application uniqueness, session management, provides some basic scriptability and desktop shell integration by exporting actions and menus and manages a list of toplevel windows whose life-cycle is automatically tied to the life-cycle of your application.
However I disagree with Dragnucs about why the GtkWindow approach is introduced in the tutorial. I tend to think simple examples with very little boilerplate are more appropriate for a tutorials Getting Started section (but, I do think that the read-the-docs tutorial needs to be updated to include at least some mention of GtkApplication).
In applications I've written I tend to either subclass both GtkApplication and GtkWindow or for single window quick-and-nasty applications just subclass GtkWindow. Your decision will depend on your applications needs.
Technical difference: There is also an important technical difference between how the two examples are implemented. The example with just a GtkWindow creates a new Gtk main loop for each instance of the program. The example with GtkApplication creates a single main loop attached to the first instance and each subsequent call to run(None) will request that the original instance create a new window (the new instance will then exit). Try opening up two terminals and running your application in each window, notice that one terminal will wait until all the windows have closed before becoming sensitive again. You can change this behaviour by using G_APPLICATION_NON_UNIQUE instead of G_APPLICATION_FLAGS_NONE.
The second code example looks unnecessary complicated to me, the first looks perfectly fine. The author of that second tutorial has put a link to another, even more simple example (Source):
from gi.repository import Gtk
window = Gtk.Window(title="Hello World")
window.connect("destroy", lambda w: Gtk.main_quit())
window.add(Gtk.Label("Hello World!"))
window.show_all()
Gtk.main()
There is nothing wrong with either approaches. You can use all the default widgets, not subclassing anything, like in the example above. Or you can subclass certain widgets, mainly as a way to give your code a nice structure and having re-usable custom/modified widgets in the end. That is all up to you.
The same applies to Qt and many other GUI frameworks, btw.
The second approach is better. It makes the application more integrated into the desktop and informs more about what it does or is meant to do. It also provides you with more tools to use with your application.
I think the first approach is just not up to date or something. The second one is really the preferred way.
You can see that the application Gnome-music is actually using the second approach with Gtk.Application usage. All the official Gnome apps are using Gtk.Application, and all Gtk application should be using it too.

Python Tkinter: Adding widgets to file dialogs

I am using Tkinter with Python 2.6 and 2.7 for programming graphic user interfaces.
These User Interfaces contain dialogs for opening files and saving data from the tkFileDialog module. I would like to adapt the dialogs and add some further entry widgets e.g. for letting the user leave comments.
Is there any way for doing so?
It seems that the file dialogs are taken directly from the operating system. In Tkinter they are derived from the Dialog class in the tkCommonDialog module and call the tk.call("tk_getSaveFile") method of a frame widget (in this case for saving data).
I could not find out where this method is defined.
call method is defined in _tkinter.c, but there is nothing interesting for your particular task there. It just calls a Tcl command, and the command tk_getSaveFile does all the work.
And yes, when there is a native file dialog on the operating system, tk_getSaveFile uses them (e.g. GetSaveFileName is used on Windows). It could be possible to add widgets there, but not without tampering with C sources of Tk. If you're sure that your target uses non-native Tk dialogs, you could add something to its widget hierarchy by hacking ::tk::dialog::file:: procedure from Tk (see library/tkfbox.tcl).
I would rather take an alternative implementation of tk_getSaveFile, written in pure Tcl/Tk and never using the OS facility. This way, we can be sure that its layout is the same for all OSes, and it won't suddenly change with a new version of Tk. It's still far from trivial to provide a convenient API for python around it, but at least, it is possible.
I had to get rid of the canvasx/y statements. That line now simply reads set item [$data(canvas) find closest $x $y], which works well. $data(canvas) canvasx $x for its own works well but not in connection with find closest, neither if it is written in two lines.

How to use dialog boxes using Glade in python running, destroying, and reusing

I am using Glade to write a python GUI with a dialog box.
If I weren't using Glade, I would use a class to create a dialog window (dialag), run it (dialog.run), do whatever it does, then removing it (dialog.destroy). I would then just re-instantiate it when I need the dialog box again.
Glade puts a monkey wrench in this. After invoking Gtk.Builder, I can get the object with something like:
dialog = builder.get_object("dialog")
response = dialog.run()
#do stuff
dialog.destroy()
I prefer the run, use, destroy way of working as it removes it from memory.
Using Glade however, after I do the above, I can't get it to work a second time because the invocation has been destroyed, and I don't know a way of getting Glade to reinstantiate it.
In past programs I've written, I've done a this:
dialog = builder.get_object('dialog')
response = dialog.run()
# use it
dialog.hide()
When I need it again, I would do a:
dialog.show()
response = dialog.run()
# do stuff
dialog.hide()
To get around this limitation, but I haven't been satisfied with this way of doing it feeling it is a bit of a hack (and I guess with Glade, everything is created in the beginning anyway). Is there a way to get the Glade libs to re-instantiate a dialog box rather than doing all this showing and hiding?
Thanks,
Narnie
Yes - you have to create a new builder object and re-load the Glade file though. One builder object creates one dialog, and if you destroy it then it's gone.
I don't necessarily think that hiding and showing the dialog is a hack. You might want to destroy and re-create if memory is a serious concern, but otherwise I don't think it makes much of a difference.

creating child windows in wxpython

I am creating a program using wxpython which entails the need to create many sub-windows for each of menubar items. I am currently creating those sub-windows by writing different class definition for each and instantiating those classes for each event. Is this better than to have wx.window? How does two compare and what are the situations where they should be used?
If each toolbar item is to open a new "window", then I would recommend a wx.Frame or wx.Dialog. You almost never need to use wx.Window directly. wx.Window is the parent of wx.Frame and wx.Dialog. As such, wx.Frame and wx.Dialog potentially add additional functionality.
Dialogs are modal and should be used when you want program execution to stop while the dialog is dealt with (like when you need to get special information to complete some task). Frames are used when you don't need to stop program execution.

are there any cross platform window toolkits for python that aren't made by crazy people?

well maybe crazy is a bit too strong of a word, but what I am asking is if there are any window toolkits out there that don't have me do this:
class MyApp(SomeWindowClass):
I really don't want to use a library made by someone who is so obsessed with objects that he/she thinks that there should be a class for the app (which there will only be one instance of, so I don't see why anyone would want to do that extra typing)
(btw, no offense intended towards anyone who agrees with the way these libraries are set up, I just really want to know if there is anything out there with a tad bit less objects)
In general GUI toolkits rely on having some form of event loop running, the Application class in these toolkits is generally in charge of that event loop and marshaling events from the underlying window manager. Sure they could call the class EventLoopManager or something, but you need it either way so its just a naming thing then. In some cases though some toolkits who often use events can occasionally be used without them, and then you certainly dont want it to be some automatic thing.
There is PyQT.
Tkinter has one object per window/dialog, not app, and requires no classes to get something painted on the screen. It does, however, have its own main loop (like all the other GUI libraries). Obligatory Hello World:
from Tkinter import *
root = Tk()
w = Label(root, text="Hello, world!")
w.pack()
root.mainloop()
PyGTK another toolkit; which is python binding of Gtk. It is well structured with having excellent window and event loop system.
A typical example to show a window
import gtk
class Application:
def __init__(self):
self.window = gtk.GtkWindow(gtk.WINDOW_TOPLEVEL)
self.window.show()
if __name__ == "__main__":
app = Application()
gtk.mainloop()
Another recommendation is PyQt; which is python binding of Qt.
Typical hello world example is
import sys
from qt import *
app = QApplication(sys.argv)
myLabel = QLabel("Hello world!", None)
app.setMainWidget(myLabel)
myLabel.show()
app.exec_loop()
PyQt and PyGtk are widely used for rapid GUI development. From my experience pyGtk is poor in the online documentation/support compared to pyQt. But both are favorite of mine.
As you see with the answers above, GUI programming is almost always heavily object oriented, and there are good reasons for this: the graphical elements share a lot in terms of how they can be positioned within one-another, caring about whether the mouse pointer is over them etc. Furthermore, the C++ kits that qt, wx, gtk et al. wrap are already structured on a class/inheritance hierarchy, so you should not be surprised that the python wrappers are also.
If you want only simple GUI elements, then you may consider easyGUI (simple message boxes, text edit, choices), triatsUI (interactive object wrappers, primarily for controlling graphical objects) , which each solve some part of the GUI interactions without explicitly having you write GUI code.
For editing the values of fields in a record-like structure, you could also investigate GUIdata.
PS: there are various graphical tools out there to let you design your GUIs and link together some of the events, e.g., QtDesigner, that can help you avoid much of the tedious class definition code.

Categories

Resources