Chapter
2: Hello World
Hello World is a simple program that contains one widget: a button.
It's
the classic 'hello
world' example XFC style. The window displayed cannot be closed by the
window manager. Instead, it can only be closed by clicking the button.
The header file for the Hello World program is <helloworld.hh>:
#include <xfc/main.hh>
#include <xfc/gtk/window.hh>
#include <xfc/gtk/widgetsignals.hh>
using namespace Xfc;
class HelloWorld : public Gtk::Window, protected Gtk::WidgetSignals
{
protected:
virtual bool on_delete_event(const
Gdk::EventAny& event);
void on_hello();
public:
HelloWorld();
~HelloWorld();
};
and the source file is <helloworld.cc>:
#include "helloworld.hh"
#include <xfc/gtk/button.hh>
#include <iostream>
HelloWorld::HelloWorld()
: Gtk::WidgetSignals(this)
{
// Sets the title of the window
set_title("Hello World");
// Set the default size of the
window
set_default_size(200, -1);
// Sets the border width of the window.
set_border_width(10);
// Creates a new button with the label "Hello World".
Gtk::Button *button = new Gtk::Button("Click me...");
// When the button receives the "clicked" signal, it
calls the on_hello() slot.
button->signal_clicked().connect(sigc::mem_fun(this,
&HelloWorld::on_hello));
// This will cause the window to be destroyed by
calling HelloWindow's inherited dispose method.
button->signal_clicked().connect(sigc::mem_fun(this,
&HelloWorld::dispose));
// This packs the button into the window (a
Gtk::Container).
add(*button);
// The final step is to display this newly created
widget.
button->show();
}
HelloWorld::~HelloWorld()
{
}
bool
HelloWorld::on_delete_event(const Gdk::EventAny& event)
{
// When the window is given the "delete_event"
signal (this is given by the window manager,
// usually by the "close" option, or on the
titlebar), the on_delete_event() slot is called.
// If you return false a "destroy" signal is
emitted. Returning true means you don't want
// the window to be destroyed. This is useful for
popping up 'are you sure you want to quit?'
// type dialogs.
std::cout << "delete event occurred" <<
'\n';
return true;
}
void
HelloWorld::on_hello()
{
std::cout << "Hello World" << std::endl;
}
int main (int argc, char *argv[])
{
using namespace Main;
init(&argc, &argv);
HelloWorld window;
window.signal_destroy().connect(sigc::ptr_fun(&Xfc::Main::quit));
window.show();
run();
return 0;
}
Compiling Hello World
If you compiled and installed XFC yourself, you will find the source
code for Hello World in the
<tutorial/chapter02> source directory along with a Makefile. If
XFC came pre-installed, or you installed it from an RPM package, you
will
find the source code in the
</usr/share/doc/xfcui-X.X/tutorial/chapter02> subdirectory. In
this case you will have to create the Makefile yourself (replace X.X
with the
version number of the libXFCui library you have installed).
To create a Makefile for Hello World, add the following lines to a new
text file
and save it using the name "Makefile":
CC = g++
CFLAGS = -Wall -O2
helloworld: helloworld.cc helloworld.hh
$(CC) helloworld.cc -o helloworld `pkg-config
xfcui-X.X
--cflags --libs`
clean:
rm -f *.o helloworld
If you cut and paste these lines make sure the whitespace before $(CC)
and rm is a tab character. When
you
compile and run this program you will see the following window appear:
Stepping through the source code
The Hello World header file includes three other header files:
#include <xfc/main.hh>
#include <xfc/gtk/window.hh>
#include <xfc/gtk/widgetsignals.hh>
Every program needs to include
the first header file. It provides access to library initialization
functions and the main event loop. The second
header file declares the Gtk::Window object and the
last header file declares Gtk::WidgetSignals, the virtual signal
handler class for Gtk::Widget.
Next, a using statement is used to open the
Xfc:: namespace so that type names don't need to be prefixed with Xfc::
using namespace Xfc;
The HelloWorld class is derived from Gtk::Window and
Gtk::WidgetSignals. The
Gtk::Window inheritance path
looks like this:
G::TypeInstance
<-
G::Object <- Gtk::Object <- Gtk::Widget <- Gtk::Container
<- Gtk::Bin <- Gtk::Window
HelloWorld redeclares the Gtk::WidgetSignals virtual on_delete_event()
handler so it can override its default
behaviour. Next,
it declares an on_hello() method that responds to button clicks.
The only other methods declared are the constructor and destructor.
The HelloWorld source file includes the following files:
#include "helloworld.hh"
#include <xfc/gtk/button.hh>
#include <iostream>
The file <xfc/gtk/button.hh> declares the Gtk::Button class.
<iostream> is the C++ header file that provides access to the
standard C++ stream objects, such as 'cin' and 'cout'.
Looking at the HelloWorld constructor, the first line sets the window
title to "Hello World":
set_title("Hello World");
Then the second line sets the initial size of the window:
set_default_size(200, -1);
A 'width' or 'height' value of -1 tells GTK+ to use the natural size
for that dimension. In this case, the height.
The next line sets the border width of
the window to 10. The border is a blank area around the inside edge of
the window where no widgets will go.
set_border_width(10);
HelloWorld inherits set_border_width() from Gtk::Container.
Next, we create a button with the label "Click me..." and connect it to
the on_hello() method using a libsigc++ slot:
Gtk::Button *button = new
Gtk::Button("Click me...");
button->signal_clicked().connect(sigc::mem_fun(this,
&HelloWorld::on_hello));
Obviously, the "clicked" signal is emitted when the button is clicked
with the mouse
pointer. signal_clicked() is the proxy signal function for
Gtk::Button::clicked_signal.
You can connect more than one slot to a signal. Here we connect a
second slot that calls the window's inherited dispose() method so that
when the button is clicked our window is destroyed.
button->signal_clicked().connect(sigc::mem_fun(this,
&HelloWorld::dispose));
Just a brief word about dispose(). When you want
to destroy a widget you call dispose(). There is no destroy
method in XFC. The name dispose is used because it better reflects
what happens when a widget is destroyed. In GTK+ 2.0, when you ask for
a widget to be destroyed it may not be destroyed immediately.
Instead, it gets marked for destruction and is disposed of later when
its reference count drops to zero.
Next we make a packing call which that tells XFC that the button is to
be
placed
in the window where it will be displayed. Note that HelloWorld is also
a Gtk::Container and a container can only contain one widget. There
are other widgets, such as boxes and tables, which are designed to
layout multiple widgets in various ways.
add(*button);
The final step in the constructor is to display
the newly created
button by making it visible:
button->show();
The on_delete_event() handler is a
bit special. It's the
predefined virtual signal handler for the 'delete_event' signal. A
delete_event is occurs when the window manager sends this
event to the application. We
have a choice here as to what to do about these events. We can
ignore them, make some sort of response, or simply quit the
application. The value you return from this handler lets GTK+ know what
action to take. By returning true we let GTK+ know that we
don't
want to have the 'destroy_signal' emitted, keeping our
application running. By returning false, we ask that the
destroy_signal
be emitted.
bool
HelloWorld::on_delete_event(const Gdk::EventAny& event)
{
std::cout << "delete event occurred" <<
'\n';
return true;
}
on_delete_event() uses a C++ console output statement to
display the message "delete event occurred". It does this
by using the output operator <<. The << causes whatever
expression is on its right side to be output to the device on the left.
'cout'
is the predefined identifier that stands for console output and refers
to the computer screen. To use cout in your program you include the
C++ header file <iostream>.
Next is the slot method that will be called when the button is clicked.
It uses a C++ console output statement to display the message "Hello
World" on the screen:
void
HelloWorld::on_hello()
{
std::cout << "Hello World" << std::endl;
}
I assume you know about the main() function. As with other
applications, all XFC applications must have
one of these:
int
main(int argc, char
*argv[]);
After the initial using statement the first line of
code calls init() to initializes the toolkit:
init(&argc, &argv);
This function initializes
the library for use, sets up default signal handlers, and checks the
arguments passed to your application on the command line, looking for
one of the following:
- --gtk-module
- --g-fatal-warnings
- --gtk-debug
- --gtk-no-debug
- --gdk-debug
- --gdk-no-debug
- --display
- --sync
- --name
- --class
Any argument it recognizes is removed from the list, and 'argc' and
'argv' are modified to make it look like the argument never existed,
allowing your
application to parse the remaining arguments.
Next, an instance of HelloWindow is created on the stack.
HelloWorld
window;
The Xfc::Main::quit() function causes the program to end.
This function tells GTK+ that it is to exit from the main event loop
when
control is returned to it. There is no need to write a method that
calls
this function. Instead, we simply generate a slot for it and connect
that slot to our main window's destroy signal. The next line
accomplishes this:
window.signal_destroy().connect(sigc::ptr_fun(&Xfc::Main::quit));
The window widget is shown last so
the whole window will pop up at
once rather than seeing the window pop up, and then the button form
inside of it. Although with such a simple example, you'd never notice.
window.show();
And of course, we call run() to start the main processing
loop
which then waits for events to come from the X server.
run();
And the final return. Control returns
here after Xfc::Main::quit() is called.
return 0;
When you click the mouse on a XFC button, the widget emits a 'clicked'
signal. In order for us to use this information, XFC sets up the
Gtk::Button 'clicked_signal' signal to catch that signal and dispatch
it
to any connected slots. In our example, when the button we created
is clicked, the on_hello() method is called first and then
the
window's inherited Gtk::Object::dispose()
method which destroys the window. This causes the window to
emit the "destroy" signal, which is caught by its Gtk::Object
'destroy_signal', which calls Xfc::Main::quit(), which
simply exits.
Another course of events is to use the window manager to kill the
window, which will cause the 'delete_event' to be emitted. This
is caught by the Gtk::Window 'delete_event_signal' which calls our
on_delete_event()
method. If we return true here, the window will be left as is
and nothing will happen. Returning false will cause GTK+ to
emit
the 'destroy' signal which of course calls Xfc::Main::quit().
The next chapter
takes you through building another XFC application: Hello Buttons, an
enhanced version of Hello World which uses a packing box to add two
button widgets to a main window.
Copyright
© 2004-2005 The XFC
Development Team |
Top
|
XFC
4.4
|
|