GTK+ and Glade3 GUI Programming Tutorial - Part 3
January 1st, 2008Writing a Basic Program to Implement the Glade File
In this part of the GTK+ and Glade3 GUI Programming Tutorial series, I will show you a very basic program that will parse the Glade file we created in Part 1 and display the main window for our GTK+ text editor. In this part of the tutorial, I will be discussing the GTK+ concepts first and then show the code in both Python and C (in different colors). If you have chosen to work in one language or the other, you can opt to skip over the code explanation for the language you are not going to use.
Contents
- Part 1 - Designing a User Interface Using Glade 3
- Quick Overview of GTK+ Concepts
- Introduction to Glade3
- Getting Familiar with the Glade Interface
- Manipulating Widget Properties
- Specifying Callback Functions for Signals
- Adding Widgets to the GtkWindow
- How Packing Effects the Layout
- Editing the Menu (or Toolbar)
- Final Touches to the Main Window
- Getting Additional Help Using Glade
- What Next?
- Part 2 - Choosing a Programming Language for GTK+ Development
- Part 3 - Writing a Basic Program to Implement the Glade File
Setting Up Your Development Environment
To work with GTK+ and complete this step of the tutorial you will need a text editor, a terminal window, the GTK+ development libraries, and optionally Devhelp, the developer's help reference. If you're new to the Linux world, welcome to lots of options. There isn't one particular editor or IDE that is the "standard". Most developers actually work with their favorite text editor and a terminal window. Although there are some "full featured" IDEs out there, you may want to stick with a plain text editor and terminal at this point so as not to be overwhelmed or tripped up by features and automated tasks the IDE might perform.
I do my work using Gedit, the default GNOME text editor. There is a plugins package available for Gedit which contains a terminal plugin and I have written Gedit Symbol Browser Plugin which allows you to quickly jump to functions in your source code. Below are Gedit screenshots from my system while working on this tutorial (click to see full-size).
Working in C
![]()
Working in Python
The development libraries you will need depend both on your distribution and whether you want to work in Python or C. Although the process can vary greatly depending on your platform and distribution, I can give you the information you need to get started. If you have problems installing any of the packages you need, post your problem or question at the GTK+ Forums or a forum for your distribution.
When it comes to development libraries with Linux, you can often get all the packages you need using your distributions package manager to resolve dependencies. For example, on Ubuntu you can likely just issue the command: 'sudo aptitude install libgtk-2.0-dev'. This command will install the GTK+ development package, it's dependencies, their dependencies, and so on.
It's important to install the "development packages". These are suffixed with "-dev" in Ubuntu/Debian and "-devel" in Redhat/Fedora. The development packages include header files and other includes that allow you to build applications which use a particular library. Just remember, "package" allows you to run applications using that library where "package-dev" or "package-devel" allows you to write applications using that library.
Another prefix you will see on packages is "-doc" such as "libgtk2.0-doc". This will be the documentation for that library and once installed will allow you to browse the documentation using Devhelp--the GNOME developer's help browser.
If you're programming with C you should install the following packages with their dependencies: build-essential, libgtk2.0-dev, libgtk2.0-doc, libglib2.0-doc, devhelp (package names may vary depending on distribution, these are for Ubuntu).
If you're programming with Python you should install the following packages with their dependencies: python2.5-dev python2.5-doc, python2.5-gtk2, python-gtk2-doc, python-gobject-doc, devhelp (package names may vary depending on distribution, these are for Ubuntu).
GtkBuilder and LibGlade
If you recall, the file we created with Glade in part 1 of this tutorial series (tutorial.glade) was an XML file describing our GUI. The actual GUI will be built by our program. Therefore, the program will have to open and parse the XML file and create instances of the widgets described within. There is already a library written to perform this task--2 libraries in fact.
LibGlade was originally the library used to parse the glade file and create the widgets described within. At the time of writing, this will still be the more commonplace method used in other tutorials and books. However, GTK+ 2.12 included an object called GtkBuilder which is essentially the same thing and is built right in to GTK+. As this is intended to eventually replace Libglade, we will be using GtkBuilder in this tutorial. However, as you learn and look at code elsewhere on the internet, keep in mind that anywhere you see LibGlade being used, GtkBuilder can be used instead.
Since (at the time of writing) GtkBuilder is relatively new, Glade does not yet support saving in the GtkBuilder format. The GtkBuilder format is still an XML file, but with a slightly different schema. That means that in order to use GtkBuilder on a glade file, we must first convert it to the GtkBuilder format. GTK+ 2.12 provides a conversion script for this process, and will already be installed on your system at this point.
You can read some of the common questions I get about all this Libglade/GtkBuilder stuff at Libglade to GtkBuilder F.A.Q..
So we now convert the glade XML file tutorial.glade to the GtkBuilder XML file tutorial.xml with the following command:
gtk-builder-convert tutorial.glade tutorial.xml
The file 'tutorial.xml' is the file we will actually parse in our program, however, we still need tutorial.glade when we want to make changes using Glade. This is only necessary until Glade supports the GtkBuilder format in a later version (They are aiming to have this ready by Glade 3.6 which you can follow along Bug #490678).
The Minimal Application
We're finally ready to write some code! Let's just recap what we've done so far.
- Using Glade, we created tutorial.glade which describes our user interface.
- We've selected which language we will use to write our program; Python, C, or both.
- We have a text editor and a terminal window available.
- We have installed the development libraries we need to program GTK+ applications.
- Using gtk-builder-convert, we converted tutorial.glade to tutorial.xml for use with GtkBuilder.
Now, before we start digging in to all the details of what each line of code does, we are going to write a minimal application just to ensure everything works and get acquainted with the development process. So, open up your text editor and type in the following...
If you're programming in C
#include <gtk/gtk.h>
void
on_window_destroy (GtkObject *object, gpointer user_data)
{
gtk_main_quit();
}
int
main (int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *window;
gtk_init (&argc, &argv);
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "tutorial.xml", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_builder_connect_signals (builder, NULL);
g_object_unref (G_OBJECT (builder));
gtk_widget_show (window);
gtk_main ();
return 0;
}
Save this file as 'main.c' in the same directory as 'tutorial.xml'
If you're programming in Python
import sys
import gtk
class TutorialTextEditor:
def on_window_destroy(self, widget, data=None):
gtk.main_quit()
def __init__(self):
builder = gtk.Builder()
builder.add_from_file("tutorial.xml")
self.window = builder.get_object("window")
builder.connect_signals(self)
if __name__ == "__main__":
editor = TutorialTextEditor()
editor.window.show()
gtk.main()
Save this file as 'tutorial.py' in the same directory as 'tutorial.xml'
Compiling and Running the Application
If you're programming in C
Since C is a compiled language, we need to use the gcc compiler to compile our source code into a binary application. In order for gcc to know where the GTK+ libraries are that it needs to link to and what compiler flags to use, we use a program called pkg-config. When we installed the GTK+ development package, a package-config file named 'gtk+-2.0.pc' was installed on our system. This file tells the pkg-config program which version of the GTK+ libraries are installed and where the include files live on our system. To illustrate this, type the following command in your terminal:
pkg-config --modversion gtk+-2.0
The output should show the version of GTK+ you have installed. On my system it shows '2.12.0'. Now let's look at what compiler flags are needed to build a GTK+ application on my system:
pkg-config --cflags gtk+-2.0
The output of that command shows a bunch of -I switches which are specifying include paths for the compiler to use. This will tell gcc where to look for include files when we use '#include' in our application. The very first one on my system is '-I/usr/include/gtk-2.0'. That means that when I use '#include <gtk/gtk.h>' in my code, gcc will be able to find '/usr/include/gtk-2.0/gtk/gtk.h'.
Anytime you use a '#include <library/header.h>' style include that is not part of the standard C library in your code, there should be a '-I/path/to/library' style option passed to gcc. These libraries can be installed in different locations based on distribution, operating system, or user preference. Good thing we have pkg-config to handle all of this for us!
Let's compile our application so far. Issue this command in the terminal (make sure you are in the same directory in which both 'main.c' and 'tutorial.xml' reside:
gcc -Wall -g -o tutorial main.c -export-dynamic `pkg-config --cflags --libs gtk+-2.0`
The '-Wall' option tells gcc to show all warnings. The '-g' option will generate debugging information which will be useful should you have a bug in your application and need to step through the code using a debugger such as gdb. The option '-o tutorial' tell gcc to generate the output executable into a file named 'tutorial'. 'main.c' is the file gcc will compile. The '-export-dynamic' has to do with how we connect signals to callback functions which will be discussed when we step through the code. And finally, the pkg-config command appears.
Notice how it is enclosed in backticks (those are not single quotes). The backtick is usually to the left of the '1' key on th e keyboard with the tilde character (~). This is telling our shell to first execute the command 'pkg-config --cflags --libs gtk+-2.0' and put the output of that command into the current command. So if you execute 'pkg-config --cflags --libs gtk+-2.0' on your system and then paste it's output onto the end of that gcc command, it would be virtually the same thing. By using pkg-config to append the include paths and library paths to our compile command, we can use the same command to compile our program on any system, regardless of where those libraries are installed.
After your application compiles, there should be a new executable file named 'tutorial' which you execute using:
./tutorial
When you do so, you are going to see several warnings from GTK, something along the lines of " Gtk-WARNING **: Could not find signal handler 'xxxxxx'". Don't worry about those for now. Those are telling use that we specified a signal handler in our glade file which we did not yet write a function for. I'll address these when we step through the code. But you should have seen your GTK+ Text Editor window show up, and clicking the 'x' in the window titlebar should properly terminate the application.
If for some reason you were not able to get the application to compile or execute, post your error messages and any other information in the GTK+ Forums.
If you're programming in Python
Since Python is an Interpreted Language we don't need to compile our program. We simply invoke the Python interpreter, which we actually do with the first line in our source code. So all we need to do to run our Python program, is change the permissions so that the file is executable and then run it. Change the permissions using:
chmod a+x tutorial.py
And now you can run it using:
./tutorial.py
you should have seen your GTK+ Text Editor window show up, and clicking the 'x' in the window titlebar should properly terminate the application.
If for some reason you were not able to get the application to compile or execute, post your error messages and any other information in the GTK+ Forums.
Stepping Through the Code
Note: You should be looking up each new function in the GTK+ reference documentation as I introduce them. Get to know that documentation, it will be your best friend. Install Devhelp, use it! I will provided a link to the online reference documentation each time I introduce a new function in case you were unable to install Devhelp.
Including the GTK+ Library
If you're programming in C
Hopefully you know enough about C programming to understand the first line '#include <gtk/gtk.h>'. If you don't, you should probably go back and work through a basic C programming tutorial before continuing with this one. By including gtk.h, we are indirectly including a multitude of header files. In fact, with only a few exceptions, we are including all of the GTK+ library and it's dependencies including GLib. If you want to know exactly what is being included just take a look at that file! Essentially, when you're looking through the reference manuals, you have access to most of the functions beginning with gtk_, g_, gdk_, pango_, and atk_.
If you're programming in Python
Hopefully you know enough about Python programming to understand the first two lines '#import sys' and '#import gtk'. If you don't, you should probably go back and work through a basic Python programming tutorial before continuing with this one. We now have access to all gtk.x classes.
Initializing the GTK+ Library
Python implicitly initializes the GTK+ library for you. In C however, we must initialize the GTK+ library before ANY call to a GTK+ function!
If you're programming in C
gtk_init (&argc, &argv);
Looking in 'main()' we see that we initialize GTK+ before anything else using the gtk_init() function.
Building the Interface with GtkBuilder
In a GTK+ application written entirely through code, that is, without the assistance of Glade or another interface designer, we would have to programatically create each widget, set the various properties of that widget, and add it to it's parent widget where applicable. Each of these steps could require several lines of code for each widget. That can be tedious. Just think about the interface we created in part 1. There are over 20 widgets defined (including all the menu items). To create all those widgets through pure code could exceed a hundred lines of lines of code once all the properties were applied!
Good thing we're using Glade and GtkBuilder. With just 2 lines of code, GtkBuilder will open and parse tutorial.xml, create all the widgets defined within, apply their properties, and establish the widgets' parent-child relationships. Once that is done we can then ask builder for the references to the widgets we want to further manipulate or otherwise reference.
If you're programming in C
builder = gtk_builder_new (); gtk_builder_add_from_file (builder, "tutorial.xml", NULL);
The first variable we declared in main() was a pointer to a GtkBuilder object. We initialize that pointer using gtk_builder_new(). This function will create a new GtkBuilder object and return the pointer to that object which we are storing in the 'builder' variable. Just about all GTK+ objects will be created in this fashion.
The builder object at this point hasn't built any UI elements yet. We can use gtk_builder_add_from_file() to parse our XML file 'tutorial.xml' and add it's contents to the builder object.
We are passing NULL as the third parameter to gtk_builder_add_from_file() because we are not going to learn about GError just yet. So we do not have any error checking yet and if the tutorial.xml file is not found or some other error occurs, our program will crash, but we'll address that later.
You will notice that after calling gtk_builder_new() to create a new builder object, all the other gtk_builder_xxx functions take that builder object as the first parameter. This is how GTK+ implements object oriented programming in C, and will be consistent with all GTK+ objects (compare that with how Python, a natural OOP language implements the same thing below).
If you're programming in Python
builder = gtk.Builder()
builder.add_from_file("tutorial.xml")
When we initialize the TutorialTextEditor class with 'editor = TutorialTextEditor()' the class's initialization method, '__init__', is called. The first thing this method does is initialize a new gtk.Builder class with gtk.Builder(). The builder instance is local to the __init__ method because once we build our UI, we will no longer need the builder object.
The builder object at this point hasn't built any UI elements yet. We use gtk.Builder.add_from_file() to parse our XML file 'tutorial.xml' and add it's contents to the builder object.
Getting References to Widgets From GtkBuilder
Once the builder has created all of our widgets we will want to get references to some of those widgets. We only need references to some of the widgets because some of them have already done their job and need no further manipulation. For example, the GtkVBox which holds our menu, text view, and statusbar has already done it's job of laying out our design and our code does not need to access it. So, we need to get a reference to any widget we will manipulate during the lifetime of our application and store it in a variable. At this point in the tutorial, we only need to reference the GtkWindow named "window" so that we can show it.
If you're programming in C
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
A couple things are happening here. First, let's look at gtk_builder_get_object(). The first parameter is the object from which we want to get an object. Again, this is how OOP is implemented in C. The second parameter is the name of the object we want to get a pointer to. This corresponds to the 'name' we specified for the widget in Glade during part 1. If you recall, we named the main application GtkWindow 'window'. So, that's what we pass to gtk_builder_get_object().
The gtk_builder_get_object() function returns a pointer to a GObject and we are storing this pointer in 'window' which we declared at the beginning of main() as a pointer to a GtkWidget. Moreover, we know that the object we are trying to get was a GtkWindow. This is why I placed so much emphasis on the 'Object Hierarchy' of widgets and GTK+ objects. If you look at the Object Hierarchy for a GtkWindow you will see that GtkWidget is one of it's ancestors as is GObject. Therefore, a GtkWindow is a GObject and it is a GtkWidget. This is a fundamental OOP concept and critical to working with GTK+.
So, the GTK_WIDGET() wrapped around the call to gtk_builder_get_object() is a convenience macro used for casting. You can cast a GTK+ widget into any of it's ancestors using one of these casting macros. All GTK+ objects will have them available. So, 'GTK_WIDGET(something)' is the same as '(GtkWidget*)something'. We're casting the pointer to a GObject returned from the call to gtk_builder_get_object() to a pointer to a GtkWidget as that's what 'window' was declared as.
Finally, the reason we declared window as a pointer to a GtkWidget in the beginning of main() rather than as a pointer to a GtkWindow is due to convention. We could have declared it as a GtkWindow* and that would have still been correct. All GTK+ widgets are derived from a GtkWidget so we can always declare a variable pointing to any GTK+ widget as such. Many functions take GtkWidget* as a paramter and many functions return GtkWidget* and thus it usually makes sense to declare your variables as such and simply cast them to the specific widget where applicable (which you'll see later).
If you're programming in Python
self.window = builder.get_object("window")
We are using gtk.Builder.get_object() to get the object named "window" from the builder. This corresponds to the 'name' we specified for the widget in Glade during part 1. If you recall, we named the main application's GtkWindow 'window'. So, that's what we pass to get_object(). We assign the returned object to self.window so that we have access to the application's window anywhere within the TutorialTextEditor() class.
Connecting Callback Functions to Signals
In part 1 we specified "handlers" for various "signals" in our interface. If you recall, GTK+ emits signals for various events that occur. This is a fundamental concept of GUI programming. Our application needs to know when the user does something so that it can respond to that action. As we'll see soon, our application just sits around in a loop waiting for something to happen. We will be using GtkBuilder to connect the signal handlers we defined using Glade with callback functions in our code. GtkBuilder will look at our code's symbols and connect the appropriate handlers for us.
In part 1 we specified a handler named 'on_window_destroy' for the "destroy" signal of the GtkWindow named 'window'. Therefore, GtkBuilder will expect to find a function or method named 'on_window_destroy'. The "destroy" signal is emitted when a GtkObject is destroyed. As we'll see in the next bit of code, our application is going to sit in an infinite loop waiting for events to happen. When the user closes the window (such as clicking the 'x' in the titlebar), our application will need to break out of the loop and terminate. By connecting a callback to the "destroy" signal of the GtkWindow we will know when to terminate. Therefore, this is a signal you will use in almost every GTK+ application you write.
Note: The method being used to connect callbacks to signals in this example is equivalent to using glade_xml_signal_autoconnect() function when using LibGlade instead of GtkBuilder.
If you're programming in C
gtk_builder_connect_signals (builder, NULL);
When we call gtk_builder_connect_signals() we pass the builder object as the first parameter as always. The second parameter allows us to pass user data (anything we want) to our callback function. This will be important later, but for now we'll just pass NULL. This function uses GModule, a part of GLib used to dynamically load modules, to look at our applications symbol table (function names, variable names, etc.) to find the function name that matches the handler name we specified in Glade.
In Glade we specified a handler for the GtkWindow's "destroy" signal called 'on_window_destroy'. So, gtk_builder_connect_signals() is looking for a function named 'on_window_destroy' that matches the signature of the callback function for the "destroy" signal. If you recall from part 1, the "destroy" signal belonged to GtkObject. Therefore, we find the prototype for the callback function in the manual for GtkObject under the 'signals' section: GtkObject "destroy" Signal. This tells us what the prototype for our callback function should look like.
Based on the prototype specified in the manual, I wrote the following function:
void
on_window_destroy (GtkObject *object, gpointer user_data)
{
gtk_main_quit();
}
So now gtk_builder_connect_signals() will find this function and see that it both matches the name of the handler we specified in Glade and has a compatible signature (takes the same arguments) as that specified for the "destroy" signal and makes the connection. Now our function on_window_destroy() will be called when the GtkWindow 'window' is destroyed.
In on_window_destroy() we just call gtk_main_quit() to properly terminate our application. This function will break out of the main loop which I will talk about more when we get there in just a bit.
Right after the call to gtk_builder_connect_signals() there was a call to g_object_unref().
g_object_unref (G_OBJECT (builder));
This is because we are no longer going to use the GtkBuilder object. We used it to construct our widgets and then we obtained pointers to the widgets we needed to reference. So now we can free all the memory it used up with XML stuff.
You'll also noticed that we are using one of those casting macros to cast (GtkBuilder*) to (GObject*). We must do this because g_object_unref() takes a GObject* as a parameter. Since a GtkBuilder is derived from a GObject (as are all widgets) this is perfectly valid.
If you're programming in Python
builder.connect_signals(self)
In Glade we specified a handler for the GtkWindow's "destroy" signal called 'on_window_destroy'. So, gtk.Builder.connect_signals() is looking for a method named 'on_window_destroy' that matches the signature of the callback method for the "destroy" signal. If you recall from part 1, the "destroy" signal belonged to GtkObject. Therefore, we find the prototype for the callback function in the manual for gtk.Object under the 'signals' section: gtk.Object "destroy" Signal. This tells us what the prototype for our callback method should look like.
Based on the prototype specified in the manual, I wrote the following method:
def on_window_destroy(self, widget, data=None): gtk.main_quit()
So now builder.connect_signals() will find this method and see that it both matches the name of the handler we specified in Glade and has a compatible signature (takes the same arguments) as was specified for the "destroy" signal and makes the connection. Now our method on_window_destroy() will be called when the GtkWindow 'window' is destroyed.
In on_window_destroy() we just call gtk.main_quit() to properly terminate our application. This function will break out of the main loop which I will talk about more when we get there in just a bit.
Showing the Application Window
Before we enter the GTK+ main loop (discussed next), we want show our GtkWindow widget as our app doesn't do much good if it's not even visible.
If you're programming in C
gtk_widget_show (window);
Calling gtk_widget_show() sets the Widget's GTK_VISIBLE flag telling GTK+ to show the widget (which will happen within the GTK+ main loop discussed next).
If you're programming in Python
editor.window.show()
Calling gtk.Widget.show() tells GTK+ to show the widget (which will happen within the GTK+ main loop discussed next).
Entering the GTK+ Main Loop
The main loop in GTK+ is an infinite loop which performs all of the "magic". This is how GUI programming works. Once we build our GUI and setup our program, we enter the GTK+ main loop and just wait for an event to occur which we care about (such as closing the window). A lot is happening inside this main loop, however, for a beginner you can simply think of it as an infinate loop in which GTK+ checks the state of things, updates the UI, and emits signals for events.
After entering the main loop, our application isn't doing anything (but GTK+ is). When the user resizes the window, minimizes it, clicks on it, presses keys, etc. GTK+ is checking each of these events and emitting signals for them. However, our application is only connected to one signal currently, the "destroy" signal of 'window'. When the window is closed and the "destroy" signal is emitted, then the GTK+ main loop will turn over control to the handler function we have connected to that signal which breaks us out of the GTK+ main loop thus allowing our application to terminate.
If you're programming in C
gtk_main ();
If you're programming in Python
gtk.main()
In Summary
- Application uses GtkBuilder to create the GUI from XML file.
- Application gets reference to main window widget.
- Application connects 'on_window_destroy' handler to the "destroy" signal.
- Application flags the window to be shown.
- Application enters GTK+ main loop (window is shown).
- User clicks the 'x' in the titlebar as a result of which GTK+ main loop emits the "destroy" signal.
- Handler 'on_window_destroy' breaks out of GTK+ main loop.
- Application terminates normally.
What's Next?
In the next part of the tutorial we will begin to move through the code a bit faster, implementing the remaining functionality of our GTK+ text editor entirely through signal handlers.
If you don't want to read along and would rather just see the final implementations:
- Glade XML file describing GTK+ text editor GUI (tutorial.glade from part 1)
- GtkBuilder XML file descirbing GTK+ text editor GUI (tutorial.xml from part 2)
- GTK+ text editor implemented using C (main.c from part 4)
- GTK+ text editor implemented using Python (tutorial.py from part 4)
Categories
Popular Posts
RSS Feeds
Archives
June 2nd, 2008 at 5:17 am
'infinate loop', 'descirbing GTK+ text editor', typos!
Otherwise big thanks for finishing part 3 :)
June 2nd, 2008 at 7:25 am
Thanks for finishing part 3, great job!
June 2nd, 2008 at 8:16 am
Thanks for this great tutorial! What's about part 4? I'm looking forward to it!
Please excuse my bad english, i'm from Germany.
Thanks, really great work!!!
June 2nd, 2008 at 8:48 am
Part 4 should come soon. Hopefully next weekend.
June 4th, 2008 at 3:00 pm
Great Tutorial! I have been looking for this for a long time. Looking forward for Part 4. Thanks!
June 4th, 2008 at 3:09 pm
hi! good tutorial!
can you help me please, i need work with numbers introduced in entry's
for example. i need add two numbers and set it a third entry
entry3=entry1+entry2
thanks a lot
sorry for my bad english i speak spanish!
June 4th, 2008 at 4:44 pm
fernando sanchez:
You will use the g_strtod function to convert the text to a number (which you get using gtk_entry_get_text). Then you can do your arithmetic and set the third entry text using either g_strdup_printf() or g_ascii_formatd() to format the number as you see fit.
June 4th, 2008 at 4:45 pm
fernando sanchez:
Also, your question doesn't really relate to my tutorial, so post these types of questions at www.gtkforums.com so that others can both see them and possible reply more quickly than I can. Good luck!
June 5th, 2008 at 9:47 am
thaks a lot! for your aswer, and sorry for the question, but that show you r a great person!
i hope in futures make questions about your tutorial. by the way is one of the best that i see
thaks again!
June 6th, 2008 at 5:43 am
Thank you very much Micah, your tutorial is great, the best one i've seen so far!
It would be great to have it linked at http://www.pygtk.org/articles.html
I'm looking forward to read the next part :)
P.D: The gtk-builder-convert bug is fixed in gtk+2.12.10
June 15th, 2008 at 11:13 am
Nice job. Congrats. It's for some iniciatives like your, FS survives and grows. Thanks and please continue your nice efforts. :-)
June 26th, 2008 at 6:50 pm
WOW!!! Good Job on the tutorial you have no idea much this helped me.
Thanks so much,
Really look forward to the rest.
July 2nd, 2008 at 7:22 pm
Outstanding effort. This is such a great tutorial - your efforts are seriously appreciated!
Looking forward to Part 4.....
July 3rd, 2008 at 8:05 pm
Thank you very much! I'm very excited to be learning from such up-to-date material!
July 10th, 2008 at 12:01 pm
can we expect a part 4 sometime soon? I have found this very useful but feel like when a tv show leaves you hanging at the end of a season. :(
Thanks for this tut though. As arbitrary said, it is great to have an up to date tutorial.
Hippy Randall
July 14th, 2008 at 9:55 pm
Hey!
Thank you very much for this tutorial. I agree, this is the best introductory GTK tutorial I've seen.
I've programmed a bit in pygtk in the past, but I was afraid of C! With your help it now seems more familiar.
I thank you once more and look forward to part 4.
Keep up the good work!
August 4th, 2008 at 12:18 pm
This is the best introductory tutorial. Thank you for the time and the effort that you have put in for this stuff. Being a beginner this tutorial was of immense help to me.
Hats of to you.
August 5th, 2008 at 9:03 am
Thank you for this awesome tutorial!
It's precise, well written and last but not least, up to date!
Wish you the best,
and I'll look forward your next tutorials.
August 7th, 2008 at 5:21 pm
Aw no part 4? I was getting into this and can't finish it now.
Thanks for parts 1-3. That was a lot of work to put together and it's just what a newb like me needs to understand how it all works. I did have one problem.
runtime error and no gui?
gtk_widget_show: assertion `GTK_IS_WIDGET (widget)' failed
posted on the forum and searching other sites so maybe I'll find the problem
Thanks again for the hard work and help. :-)
August 11th, 2008 at 5:25 am
Great Work Carrick!!
Well written and excellent for starters...Again really awaiting ur part 4!!
Cheers again dude!
August 16th, 2008 at 12:11 pm
Thanks !! A LOT!!!
August 19th, 2008 at 2:12 pm
Amazing tutorial indeed!
It is really plain, a pleasure to read and gives a pretty nice introduction to the argument.
I am looking forward for part 4. When can we expect to see it published?
Thanks a lot!
August 19th, 2008 at 2:19 pm
GTK+ is so versatile.
August 23rd, 2008 at 10:20 am
Great Tutorial, really easy to follow, though I did have some trouble finding the right dependencies at first. Cant wait for part 4.
Thanks for all the time and effort you've put into all your tutorials, greatly appreciated by all.
August 27th, 2008 at 6:50 am
Hey everybody. Thanks for the positive feedback. I'm sorry it's been taking so long. I'm very busy in my day job at the moment and have not had time to finish. I haven't forgotten though!
August 27th, 2008 at 8:10 am
It was paradise for me too to find your tutorial ;)
Happy to find news from you today, waiting for your part 4, bye and thanks.
September 4th, 2008 at 1:36 am
Hope you finish part 4 soon, this is guru-stuff. I've gone through parts 1-3 a dozen times...
September 4th, 2008 at 10:06 am
Hi Micah,
that's a very good tutorial; as I really mainly needed to understand glade I pressed on directly to the source code in c;
I've got one question though, that is unclear: when you gtk_builder_connect_signals(), how do you know what type of object should be in the function prototypes? As all the callbacks in the tutorial are connected to Menu items, all the relevant functions accept a GtkMenuItem *; ISTR the last time I was hand coding a gtk+ application, it was a case of invoking g_signal_connect() / g_signal_connect_swapped(), with GtkWidget *, how so?
thanks
Mark
September 5th, 2008 at 8:26 am
Mark:
The function prototypes are defined in the manual. However, you need to remember GTK's object oriented characteristics. When a signal callback prototype takes a GtkMenuItem as a parameter, it takes a GtkWidget as well since a GtkMenuItem IS a GtkWidget.
Using gtk_builder_connect_signals() effectively calls g_signal_connect() on every signal handler you defined in glade. Therefore, each callback will have the exact same user_data. Using a struct is a good, simple way to make sure each callback has the data it needs. So, the prototypes will be the same as they are in the manual along with your user_data. If you need more control than that, say to use g_signal_connect_swapped() or to have different user_data going to different callbacks, you can define your own connect function for GtkBuilder.
September 6th, 2008 at 3:33 am
Hi Micah
Great tutorial. One thing that might be worth including though is the shebang line in the first python source example. I know this isn't intended to be a python tutorial but for someone (like me) looking to use this tutorial as a starting point for understanding python & gtk development, it may not be too clear why the file will not interpret correctly.
For anyone who copied and pasted the code directly and found it gave errors such as 'command not found', the reason is that bash is being used to interpret the code. to make python interpret it, you need to add the following to the very first line, before any other code:
#!/usr/bin/python
Again, great tutorial, it's been really helpful.
September 8th, 2008 at 4:20 am
hey Micah!!!
You tutorial clear my Callback related funda's, specially ur answer to Mark's reply.
It will help me to write code using gtk+ and glade-3.
It took 3 days to understand basic of gtk+ and run my first gtk+ gui application.
Thank a lot.
September 8th, 2008 at 4:52 pm
Micah,
Unbelievable tutorial! Very professional and the best I've ever come across.
I've done a lot of GUI development in M$ Dev Studio so its taking me a little bit of time to get used to how widgets get laid out. I've really been wanting to write some Linux apps for a change and your tutorial is just what I was looking for. I'm looking forward to part 4 as well!
Maybe you should write a book? I'd buy it!
A Million Thanks!
Charlie
September 11th, 2008 at 1:52 pm
Micah-
Brilliant tutorial. I never would've gotten any of this working without it.
I did have a bit of difficulty getting gtk_builder_connect_signals to work properly. My program compiled and linked fine, but at runtime, gtk always gave me something like the following warning for all of my signal handlers:
Gtk-WARNING **: Could not find signal handler 'some_handler'
I tried just about every combination of various flags I could find mentioned on the subject (searched for 2 days), but the thing that finally worked was adding gmodule-export-2.0 to your pkg-config recommendation from above:
pkg-config --cflags --libs gtk+-2.0 gmodule-export-2.0
Anyway, if anyone else had that problem, I just wanted to make sure it ended up in the search engines somewhere.
Thanks for all your hard work!
-Josh
September 17th, 2008 at 6:59 am
Thanks for your feedback. As a matter of fact, I have several GTK+ related book ideas and am working on sample chapters for one of them. However, I haven't had much free time this year yet, so they are slow coming.
But thanks for your encouragement.
September 17th, 2008 at 7:01 am
Josh: What operating system, GTK verison, and distribution were you using which required the gmodule-export-2.0? Was that on Windows?
September 17th, 2008 at 8:06 am
I'm running Ubuntu Linux 8.04 and GTK 2.12.9 (according to the GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION macros).
September 19th, 2008 at 5:09 am
I was also getting errors with all the signal handlers like Josh. I tried the pkg-config suggestion and that fixed it.
Thanks Josh, and thanks Micah for a great tutorial.
September 28th, 2008 at 4:30 am
Hey Micah,
Looking to implement your tutorial and the tutorial.py. The 'problem' is that I am using Windows . know how I can use gtk-builder-convert over here ?
October 19th, 2008 at 6:30 pm
Nice tutorial. Too bad you didn't have time to finish it though, just when I was getting into it.
No problem, I understand you might have little time to work on this. Thanks for writing those three parts.
I'll try and have a look at the part4 files there and make some sense out of it.
Thanks a lot.
October 27th, 2008 at 11:06 am
Just wanted to say that your tutorial helped a lot to demystify GUI programming for me. Thanks!
-Phill
October 28th, 2008 at 5:29 am
Micah: Thanks a lot for this wonderful tutorial and for the gedit plugin it is very useful
I have a problem when adding c++ code to the program. It seems that the signals do not connect.
This is what I did: I just rename your main.c example to main.cpp and compiled it in the same way.
gcc -Wall -g -o tutorial main.cpp -export-dynamic `pkg-config --cflags --libs gtk+-2.0`
It does compile and run but it does not find the on_window_destroy signal then when closing the form the program does not end since the on_window_destroy signal is not connected.
I have try gtkmm (www.gtkmm.org/) but is seems that it does not have a gtk_builder_connect_signals function and all the signals have to be connected manually,
Do you have some advice on how to use c++ code and gtk+?
Regards
Mario
November 1st, 2008 at 8:18 pm
I am trying to change an image widget's ".jpg" file and built a simple application to do this but cannot get the function to work. I know the fuction runs because of the dialog box which shows up when I click on the button. But I cannot get the image file to change from the "Off.jpg" to the "On.jpg". It compiles without complaint but won't work. I have attempted using Anjuta IDE but it only complicates matters as I am an ignorant about how they interface with glade 3. I am running a Dell laptop with Ubuntu 8.04 and the latest gtk/glib files. Can you put me on the right track?
These are my files.
XML:
True
True
True
True
button
True
Off.jpg
1
MAIN.C
#include
void
on_window_destroy (GtkObject *object, gpointer user_data)
{
gtk_main_quit ();
}
void
on_button1_clicked (GtkButton *button, gpointer user_data)
{
GtkBuilder *builder;
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "widgets.xml", NULL);
GtkImage *image = GTK_IMAGE(gtk_builder_get_object(builder, "image1"));
gtk_image_set_from_file ( image, "On.jpg");
/* Create the dialog widget */
GtkWidget *dialog, *label;
//image = GTK_IMAGE_IMAGE(image), "image1";
dialog = gtk_dialog_new();
label = gtk_label_new (" Check Button ");
/* Ensure that the dialog box is destroyed when the user responds. */
g_signal_connect_swapped (dialog,
"response",
G_CALLBACK (gtk_widget_destroy),
dialog);
/* Add the label, and show everything we've added to the dialog. */
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
label);
gtk_widget_show_all (dialog);
}
int
main (int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *window;
gtk_init (&argc, &argv);
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "widgets.xml", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_builder_connect_signals (builder, NULL);
g_object_unref (G_OBJECT (builder));
gtk_widget_show (window);
gtk_main ();
return 0;
}
November 20th, 2008 at 4:00 am
I had the same problem with signal handlers (on Ubuntu 8.04). gmodule fixed it. Cheers
November 20th, 2008 at 3:49 pm
Great job! Looking forward to Part 4
November 21st, 2008 at 9:59 am
Just finished reading these three great articles from you. a few chapters with examples provide me a quick start. and most of all, i don't lose interest. many thanks!
November 27th, 2008 at 1:36 am
Hi Micah, I can't understand why it's no possible to behave the same with the error_dialog and the about_dialog... in the first case u just run() and then destroy() but in the second u have to write callbacks and so a lot of code... I tried to run() and destroy() the about_dialog too but it worked only the first time, when I close and open the dialog again it freezes.
Regards & thanks.
Giuseppe.
November 27th, 2008 at 6:45 am
Reagarding Mario's post:
"I have try gtkmm (www.gtkmm.org/) but is seems that it does not have a gtk_builder_connect_signals function and all the signals have to be connected manually,
Do you have some advice on how to use c++ code and gtk+?"
you can connect signals like this:
//Load the GtkBuilder file and instantiate its widgets:
Glib::RefPtr refBuilder = Gtk::Builder::create();
refBuilder->add_from_file("gladefile.xml");
gtk_builder_connect_signals(refBuilder->gobj(), NULL);
November 28th, 2008 at 9:30 am
Hi Micah,
Thank you for an excellent tutorial. Written and presented in a style that makes it a joy to read and follow. I'm a novice with regard to Glade and Linux, and I'm also a fairly inexperienced C programmer but the content of your tutorial made it a breeze for someone like myself to follow and to produce a working program. I have downloaded, read and compiled the 'to be released' tutorial 4 c source code and now have a full working text editor.
I attempted to load an executable file into the editor to see what the result might be. The same view is displayed for all executable binaries, 'ELF with a couple of other characters'. The GTK+ Devhelp manual contains a conceptual overview of the text widget in GTK+ and mentions that text is in the UTF-8 encoding. Is it possible to use the GTK+ text view to display the ELF file as a hexdump, or as disassembled code, and if so, how might this be achieved.
Regards,
Steve
December 13th, 2008 at 5:57 am
Micah,
No need to reply to my first post. The guys at Gtk forums have already been a great help. I am currently
developing my application using your text editor program as a basis. I already have a full working program capable of parsing binary files to extract and display relevant information in a nice Gnome windowed environment.
Once again...thanks for a superb tutorial.
Steve
December 23rd, 2008 at 2:24 am
I was running the same sample program but getting an error :" ‘GtkBuilder’ undeclared (first use in this function)"
so I am not able to proceed further please help me to find the solution.
December 25th, 2008 at 7:11 am
Micah,
Great work so far... Hope you have time to finish chapter 4 over the holidays.
John
December 27th, 2008 at 6:33 pm
Great job!Really helpfull!you should write a book or somethink about pygtk!!You reall have the qualifications for it!!Thanx again!
January 3rd, 2009 at 6:19 pm
Micah,
I just stumbled across this tutorial yesterday.
I have been looking for a quick tutorial like yours that is clear, concise and has all the elements needed to get started and it is very well written.
Thank you, and if there is a part 4. I can hardly wait.
Willy
January 5th, 2009 at 1:12 pm
Hi,
My C file compiles and runs fine with this command:
gcc -Wall -g -o tutorial main.c `pkg-config --cflags --libs gtk+-2.0` -export-dynamic
But I get an error that "GtkBuilder" is undeclared when building with CMake. Here's my C file (CMake file is below):
---------------------------------------------------------------------
#include
int main (int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *window;
gtk_init (&argc, &argv);
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "MainWindow.xml", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_builder_connect_signals (builder, NULL);
g_object_unref (G_OBJECT (builder));
gtk_widget_show (window);
gtk_main ();
return 0;
}
---------------------------------------------------------------------
I'm using CMake to build my projects and now started with GTK programming. Here's the extract from my CMakeLists.txt file that builds my GTK application. It is very ugly, I know.
---------------------------------------------------------------------
option(opt_build_gtk_viewer "Build the GTK/OpenGL viewer" ON)
if(opt_build_gtk_viewer)
find_package(GTK)
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
if (OPENGL_FOUND AND GTK_FOUND AND GTK_GL_FOUND)
include_directories(
${GTK_INCLUDE_DIR}
${OPENGL_INCLUDE_DIR}
${GLUT_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
/usr/include/gtk-2.0
/usr/lib/gtk-2.0/include
/usr/include/atk-1.0
/usr/include/cairo
/usr/include/pango-1.0
/usr/include/glib-2.0
/usr/lib/glib-2.0/include
/usr/include/pixman-1
/usr/include/freetype2
/usr/include/libpng12)
add_executable(
gtk_viewer
viewer/main.c)
target_link_libraries(
gtk_viewer
${GTK_LIBRARIES}
${GLUT_LIBRARIES}
${OPENGL_LIBRARIES}
freeimage
gtk-x11-2.0 gdk-x11-2.0 atk-1.0 pangoft2-1.0 gdk_pixbuf-2.0 m pangocairo-1.0 gio-2.0 cairo pango-1.0 freetype z fontconfig gobject-2.0 gmodule-2.0 glib-2.0
GLEW)
else()
message("The GTK/OpenGL viewer cannot not be build because GTK/OpenGL/GLU/GLUT was not found.")
endif()
endif()
January 5th, 2009 at 1:23 pm
I found the answer to my question above: CMake is only capable of finding GTK1.2 but not GTK2. Therefore I changed my CMakeLists.txt like so:
Remove this line:
find_package(GTK)
Add this line instead:
PKGCONFIG(gtk+-2.0 GTK2_INCLUDE_DIR GTK2_LINK_DIR GTK2_LINK_FLAGS
GTK2_CFLAGS)
Replace
${GTK_LIBRARIES} with ${GTK2_LIBRARIES}
and
${GTK_INCLUDE_DIR} with ${GTK2_INCLUDE_DIR}
That's it.
January 10th, 2009 at 2:40 am
Hi Micah,
Great tut! I made a gtk-program a while ago and it took me about 20 hours of research to get ANY information... then, two weeks later i found ur tutorial and finally understood what i was doing in that program :-)
Thanks alot!
grretings
Lanna
PS: Please excuse my bad English.... im German
January 23rd, 2009 at 3:19 pm
Hi Micah,
The tutorials you have been providing are outstanding. If its not too much trouble, can you add a section showing how to grab information entered into a widget inside that widgets signal handler? For instance, when implementing a checkbox, how to identify if the checkbox is checked or unchecked in the handler upon a toggle.
Thanks,
Jake
January 28th, 2009 at 4:44 pm
Micah,
I just got through the 1st 3 tutorials - great work. How do I complete the event links?
I tried this:
static gboolean on_window_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{return TRUE;}
got 2 warnings from gcc:
parser does not support -dy, otpion ignored
"on_window_delete_event" defined but not used.
Thanks,
Bob M
February 13th, 2009 at 6:57 pm
When will you finish part 4? Eagerly awaiting!
March 13th, 2009 at 7:22 am
Sir I am developing an application using C/GTK+. In that application i have a window which consists of few entry boxes and i have set the values inside those entry boxes. I have done all this thing inside the main().
But i want to change the values of the entry boxes when i call a function. I don't want to recreate the window and the entry box but i just want to change the values of those entry boxes.
Please help me i am in an urgent need.
Thanking you
March 20th, 2009 at 8:10 am
Thanks a lot. It really give me much clearer understand about Glade...
It seems there's Part4, isn't it? Have you upload it?
March 24th, 2009 at 10:28 pm
Hi all, if you're doing this tutorial on windows and you get a "could not find signal handler" error, try changing
void
on_window_destroy (GtkObject *object, gpointer user_data)
{
gtk_main_quit();
}
to
G_MODULE_EXPORT void
on_window_destroy (GtkObject *object, gpointer user_data)
{
gtk_main_quit();
}
March 25th, 2009 at 8:25 pm
This post is exactly what I was looking for. Thank you very much.
April 5th, 2009 at 7:33 pm
Is there 4th part, it would be nice to understand how to design the app. When do you decide on the signals, do you first build the app then the gui. What is the most effective way of going about it.
April 7th, 2009 at 7:18 pm
Great tutorial! Your writing is excellent and interesting to read. This has been a huge help in getting me started on GTK and Python development. Can't wait for the next part!
Thanks
April 13th, 2009 at 4:32 pm
Dear Micah,
Thank you for writing so much about GTK and Glade, it has really been a lot of help! I found more useful information about setting up an Anjuta GTK Project in your tutorials than on the Anjuta official pages.
One small critique I would add is about the organisation of tutorials - there are so many of them with only small differences and they reference each other in a way that wasn't too intuitive to me. Maybe if you wrote an index with short descriptions of each one with differences that wold send any newcomers to the right direction. Afterwards maybe put a link to that index at the beginning of each tutorial so that everyone would see it.
Also I would like to give a suggestion for the future - the newest tutorials about Glade 3 are only covered for terminal programming, not for the Anjuta IDE 2.24. It would be very good if you wrote something about that, for those of us who prefer IDEs to cowboy-style-terminal-programming :) (when I followed the steps of this tutorial, only in Anjuta it wasn't all that hard, but it took me some experimenting to figure it all out - egg. that callback functions go to callbacks.c, that I don't have to start gtk window myself, that code is already there, etc. :P)
In the end, one question... I am trying to make a representation of a list of contacts (for a Skype-like application). All the data is in the data structures - names, pictures, etc. How can i for example put pictures of the contacts in the window of the application? Do I have to call some functions to draw them inside? If it's not too big of a trouble, please direct me in what direction should I continue reading to figure it out.
Yours sincerely,
Dražen
June 8th, 2009 at 6:15 pm
Again, Dear Micah.
You don't know how much you've just learned me in very few words! I enjoyed it from the beginning to the end and makes me wonder 2 things:
1. Where's part 4 ?
2. Where's your donations button? I owe you one ..
June 11th, 2009 at 11:07 am
Hi Micah
Just about the best tutorial i have seen for quite a few years. Well structured, the right level of detail (for me at least), good explanations. I can't wait to get started.
Thanks