Introduction to programming in Fltk |
All public symbols in fltk start with the characters 'F' and 'L':
Fl::foo()
or fl_foo()
.
Fl_Foo
.
FL_FOO
.
<FL/...>
.
I intend someday to put all the public symbols of fltk in to a
C++ namespace "Fl::". Currently many compilers do not
support namespaces. I simulate a portion of the namespace with a
dummy "class Fl" but most symbols are not in it because they would all
have to be in the same header file. The change to namespaces will be
incompatable and will require replacing all occurances of
fl_
or
Fl_
with 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_Window
s 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.