Wednesday, August 04, 2010

A Quick try of Gtkmm

Okay I figure I would give my hand a try at some Gtkmm. The API is pretty much like most curses and Java Windowing framework. So let's do a quick sample.

Let's start with our header file for the Window, we'll call it window1.h


#ifndef WINDOW_1_DEF_H
#define WINDOW_1_DEF_H

#include<gtkmm/window.h>
#include<gtkmm/button.h>
#include<gtkmm/entry.h>
#include<gtkmm/box.h>

class Window1 : public Gtk::Window {

public:

Window1();
virtual ~Window1();

protected:

void on_button1_clicked();

private:

Gtk::Button button1, button2;
Gtk::Entry entry1;
Gtk::VBox vbox1;

};

#endif



All of that should explain itself. Basically the object is a Gtk::Window, which is the top level container (widget, whatever you want to call it). We are adding two Gtk::Button, a Gtk::Entry (text entry widget), and a Gtk::VBox which is the layout container.

Now the fun thing about Gtkmm is that you don't have to "new" objects into existence. Instead Gtkmm will handle the memory allocation for you in most cases!! However, if you need to dynamically allocate objects or you need them outside of the class scope then your own your own, unless you use the Gtkmm smart pointer Glib::RefPtr<>, which is basically the same as the std::auto_ptr<> for those of you who have studied standard C++.

Okay let's implement the window, this will be in most logically window1.cc


#include "window1.h"
#include <iostream>
#include<gtkmm/main.h>

Window1::Window1() : button1("Print"), button2("Ouit") {

set_size_request(200,100);
set_title("Text Entry Demo");

add(vbox1);

entry1.set_max_length(25);
entry1.set_text("Enter something");
entry1.select_region(0,entry1.get_text_length());

vbox1.add(entry1);

button1.signal_clicked().connect(sigc::mem_fun(*this,&Window1::on_button1_clicked));
button2.signal_clicked().connect(sigc::ptr_fun(&Gtk::Main::quit));

vbox1.add(button1);
vbox1.add(button2);

show_all();
}

Window1::~Window1() {
using namespace std;
cout << "Say goodbye" << endl;
}

void Window1::on_button1_clicked() {
std::cout << "You have entered: " << entry1.get_text() << std::endl;
}



Okay this one has a couple of things to cover. Like what the heck is the sigc namespace?!

sigc is the library that Gtkmm uses to implement callbacks. A callback is a function or method that is called from another function. Basically the on_click method of your buttons gets called when you click on them. The method basically says, when I'm clicked run ________(insert blank line)________. The callback fills in the blank line.

Now historically there is basically one way to do this in C, but in C++ there must be at least a dozen libraries that do this. I won't get into why this is because that's a much bigger topic.

At anyrate, sigc is the tool that Gtkmm has chosen to implement callbacks. sigc has two ways to add callbacks. mem_fun and ptr_fun, both used here. mem_fun, allows you to call a method and ptr_fun allows you to call a function. Pretty clear cut there. As you can see I've connected the button2's click to the Gtk::Main::quit, which of course does what it says. Quits.

The other button, button1, I've connected to the on_button1_clicked method. This method simply uses standard C++ cout to write information to standard out. You may notice that I use the entry1.get_text() method within the on_button1_clicked() method and that I don't cast it's result to std::string. That's the neatest part of Gtkmm is that it was made to work with the C++ STL so well. Gtkmm already implements the logic needed to cast Glib::ustring (which is what the get_text() wethod returns) to std::string.

The rest of the code is pretty simple to follow.

So now that we have implemented our window we need an application that actually uses it.

I present main.cc


#include<gtkmm/main.h>
#include"window1.h"

int main(int argc, char *argv[]){

Gtk::Main kit(argc, argv);
Window1 w;
Gtk::Main::run(w);

return 0;
}



This is as basic as you can make an application that uses our window.

The results are here.


Clicking on the Print button outputs the text box on standard out and clicking quit, well quits. As you can see Gtkmm is very much like most other Toolkits, semantics are a little different here and there and you'll use some of the core tools of Gtkmm a little differently but overall you'll easily see how Gtkmm compares to things like SWT, Swing, and QT.

And since I said something about QT, it's worth saying something about it. If you have ever used QT then you know about it's signal/slot system and moc. Well Gtkmm takes the "high road" on this one and uses sigc to implement callbacks in a C++ standard-ish kind of way. The downfall of this, however, is that every callback must be statically typed. This amounts to a lot of double work. If you implement a signal connection in Glade, you must also implement that connection in Gtkmm by importing the widget and then using sigc.

I know this is one of the downfalls of C++'s strong type safety system and name mangling system. QT gets around this with moc but then using moc makes your code non-C++ standard compliant, which I don't think anybody really has a problem with except the people behind Gtkmm.

At anyrate, at risk for getting way off topic, Gtkmm is a neat little wrapper around Gtk+ and you should give it a whirl. You'll be making Gtk+ applications in no time, and best of all is the Gtkmm library works on Windows, Mac, Linux, BSD, and other Unix systems.
Link to Gtkmm

No comments: