I'm fairly new to GTK, and am messing around with my first "serious" GTK (gtk+-3) app. I'd like to draw on the wisdom of others' experience about when it's suitable to define a new GTK class, or just use a "vanilla" GTK classes, and implement behaviour via signal handlers.
I've come across two examples so far:
I'm creating a new widget: basically a GtkDrawingArea, which I use to display some data. I had originally assumed that the best way to implement this would be to subclass GtkDrawingArea, using G_DEFINE_TYPE
, and provide my own draw callback:
static void mywidget_class_init(MyWidgetClass *klass)
{
GTK_WIDGET_CLASS(klass)->draw = mywidget_draw;
}
However, it looks like I could implement exactly the same functionality without defining a new type, by just creating a vanilla GtkDrawingArea, and hooking up the appropriate signals during initialisation.
[My custom widget will eventually provide more than just the draw callback, as it needs to be interactive, but that comes later...]
My application consists of a few different windows, which currently are vanilla GtkWindows:
struct myapp_somewindow {
struct myapp *app;
GtkWindow *window;
GtkWidget *some_label_that_is_updated;
/*... other window-specific fields */
}
When the myapp_somewindow struct is initialised, I create the GtkWindow with gtk_window_new()
, and initialise the widgets/layouts/etc, and connect the signals. [I'll probably be using .ui files for the more complex cases eventually, but the windows are simple enough for now.]
This could be done my defining a new subclass of GtkWindow, but I'm not certain when the code overhead of defining the new class becomes worthwhile.
I'm aware that there's probably no strict rules for which approach to take, but are there any general guidelines to use when making these design decisions? Are there any major pitfalls of either approach?
I've worked on a fair few projects using GTK+ and Clutter and i've always promoted heavy use of subclassing of generic widgets / actors to more specific ones.
By convention with GObject you create a new file for each class and thus if you pull in the behaviour and state mechanics associated with your widget into a subclass you will pull that code into a separate file. This helps make it easier to structure your code and helps when someone else wants to come along and read it.
The subclassing strategy also helps you enforce encapsulation as a good practice on your code base. If your widgets and their associated state and logic are well encapsulated then that can help with reuse.
A good example of a project where this subclassing strategy has been used is tasks, and in particular it's internal helper library: http://git.gnome.org/browse/tasks/tree/libkoto This meant that when we wanted to port the application to a new platform or provide a different view on the data it was quite easy to just glue the existing widgets and tree models together in a different way.
If you want to use C and you find subclassing a bit tedious then you can try this tool: http://git.gnome.org/browse/turbine/ to help automate the creation of your subclasses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With