All the widgets have several attributes and there is a method for
setting and getting the current value of each of them.
labelfont() is
set to a symbolic value which is compiled into a constant integer, 3
in this case. All properties that cannot be described by a single
small number use a 1-byte index into a table. This makes the widget
smaller, allows the actual definition of the property to be deferred
until first use, and you can redefine existing entries to make global
style changes.
labeltype(FL_SHADOW_LABEL)
also stores a 1-byte symbolic value, in this case indicating a
procedure to draw drop shadows under the letters should be called to
draw the label.
The constructor for widgets adds them as children of the "current
group" (usually a window). window->end() stops adding
them to this window. For more control over the construction of
objects, you can end() the window immediately, and then add the
objects with window->add(box). You can
also do window->begin()
to switch what window new objects are added to.
Fl::run() makes FLTK
enter a loop to update the screen and respond to events. By
default when the user closes the last window FLTK exits by calling exit(0). run() does not
actually return, it is declared to return an int so you can end your
main() function with "return Fl::run()" and outwit the stupid compiler
made by a certain very large software company.
The following command compiles this program, assuming the FLTK
library has been put in /usr/local/lib and the header files in
/usr/local/include/FL:
The first thing your program should do is construct one or more
trees of Fl_Widgets. The base widget of each of these is
an Fl_Window widget. The constructors for widgets
automatically add them as children of the most recent created window
widget (use window->end() to stop this). Constructing the widgets
does not require the display to be open and does not open it,
unless you purposely open it to get information such as the width of a
font.
Fl_Windows are displayed on the screen with
Fl_Window::show(). For the first window you may also use
Fl_Window::show(argc,argv) and FLTK will automatically
parse some startup arguments such as -display.
Then the program repeatedly calls Fl::wait(). Each
time "something happens" Fl::wait() returns, usually after
a block of X events have been read and processed. It is often useful
for a program to check global state after each event, and FLTK makes
this easy by leaving the main loop under your control.
Each widget has a single "callback". This is a function that
is called when something happens (such as the user pressing a button).
FLTK avoids all the complexities of signals/slots by having only a
single callback. Instead a when() method on the object selects when
the callback is done (ie. when a slider is moved or when the mouse is
released).
The callback is passed a pointer to the widget and a void* user_data
field. This is redundant, as the user_data can be determined from the
widget, but was done for XForms compatability and to make the same
callbacks useful for menu items. Typically you want to turn the
callback into a method on some C++ object. A simple way is to use the
user_data as a pointer to the object. A more common but harder to
understand way is to store the object in the parent widget's
user_data field, since usually all the controls on a window are for the
same object, this lets you use the user_data for an abitrary method
argument.
To display graphic data, you must subclass either
Fl_Window or Fl_Widget and define the virtual
draw() method. This can use functions defined in
<FL/fl_draw.H>, or can use system-specific calls such as Xlib. If
the data being displayed changes, your main program calls the
redraw() method on your widget, and FLTK will call
draw() while waiting for the next event. Subclassing
Fl_Window or Fl_Widget is so easy that I felt
it unnecessary to provide the "canvas" widget that most toolkits have.
If your program needs to monitor another device (such as stdin) you
can provide a callback routine for when it becomes ready, by using
Fl::add_fd(i). If your program needs something to happen
at regular intervals you can define a timeout callback with Fl::add_timeout(time).
Building a large hierarchy is made much easier with fluid
(the Fast Light User Interface Designer). This is a program that lets
you interactively design the widget layout and set all the properties
visually. It outputs C++ source code that you compile and link with
your program. All you have to write is the main loop and any
callbacks.
box->labelsize(36) sets the labelsize() to 36. You could get
the value with box->labelsize(). Often you have to set
many properties, so you will be relieved to know that almost all of
these methods are trivial inline functions.
window->show()
finally
puts the window on the screen. It is not until this point that the X
server is opened. FLTK provides some optional and rather
simple command-line parsing if you call show(argv,argc). If you don't want this, just
call show() with no arguments, and the unused argument code is not
linked into your program, making it smaller!