Suppose you have an application that uses a lot of GtkFileChoosers. If someone chooses a file, you want your program to remember the directory they were last in next time they open a file chooser.
Simple you think, you'll just set the current folder before you show the chooser and get the current folder after the user has made their selection. Of course, this means you'll have to put that code around every GtkFileChooser instance.
The solution is subclassing.
By creating a subclass, we can override methods like the constructor and run() to hook in our directory save and restore code. We can also set default properties that would otherwise be required for every instance. The method for subclassing an object depends on the language you're using, but is possible even in C. For this example, I'll use Python:
class MyFileChooserDialog (gtk.FileChooserDialog):
CWD = None
def __init__ (self, *args, **kwargs):
super (MyFileChooserDialog, self).__init__ (*args, **kwargs)
# set some defaults
self.set_default_response (gtk.RESPONSE_OK)
self.set_property ('do-overwrite-confirmation', True)
# set the working directory if available
if MyFileChooserDialog.CWD is not None:
self.set_current_folder (MyFileChooserDialog.CWD)
def run (self):
response = super (MyFileChooserDialog, self).run ()
# get the working directory if the user clicked ok
if response == gtk.RESPONSE_OK:
MyFileChooserDialog.CWD = self.get_current_folder ()
return response
gobject.type_register (MyFileChooserDialog)The class being created is MyFileChooserDialog, which inherits from GtkFileChooserDialog. It has a class-global variable called CWD. The constructor accepts all arguments it is called with, and passes them unmodified to the parent's constructor. It then sets some default properties and finally, sets the current folder for the instance to the global variable CWD.
The run() method also immediately calls its parent's method. It then checks the response code, if the user didn't cancel the action, we store the instance's current folder in the global CWD and then return the value from our parent. All other methods from the parent work as usual, allowing us to transparently replace all instances of gtk.FileChooserDialog with MyFileChooserDialog.
New methods, not implemented in the parent, can also be added to the class. Or depending on your language, new polymorphic methods to support additional data types could be implemented. Python doesn't have true polymorphism, but say we wanted to extend the functionality of add_filter() to make it easier to use in our app:
def add_filter (self, filter, *args):
if isinstance (filter, gtk.FileFilter):
super (MyFileChooserDialog, self).add_filter (filter)
elif isinstance (filter, MyFileChooserFilterEnum):
pass # do something with an enum
else:
super (MyFileChooserDialog, self).add_filter (create_filter (filter, *args))
def create_filter (name, *patterns):
filter = gtk.FileFilter ()
filter.set_name (name)
for pattern in patterns: filter.add_pattern (pattern)
return filter
Allowing us to do something like
dialog.add_filter ("X Files", "*.x") to create the GtkFileFilter on the fly.
Subclassing allows us to extend the functionality of widgets in reusable way.
Play Along At Home: feel free to port this example into your language of choice, comment with text or a link!