559
HANDS-ON TUTORIAL:
Since FLTK is
a graphical user interface toolkit, its main purpose is to create
interfaces. In most cases, this
involves creating windows with widgets ( buttons, sliders, dials, browsers,
etc. ) on them. FLTK provides a way to
create an event driven program based on these interfaces. Although FLTK provides many classes for
specific widgets, one of its beauties lies in the fact that you can inherit
from these classes. Through inheritance,
you can override certain functionalities of each widget, and configure it to suit
your own application, without the need to code everything from scratch. As you go through this tutorial, keep in
mind that these are specific examples to help you see and learn FLTK. The most important piece of information you
should come away from this tutorial with is how to build interfaces. It is not as important that you create the
specific files that are mentioned in this tutorial.
The first
thing we are going to need in order to produce an interface is a Visual C++
workspace.
Using the FLTK Tutorial (http://www.cs.wisc.edu/~cs559-1/Notes/fltktut.html) from last year, create a new FLTK Work Space
in Visual C++ 6.0.
Now that you have created a workspace to build
interfaces, let’s create a very basic interface. The most basic interface consists of just a window by itself.
1.
Choose
File->New
2.
Click
on the Files Tab at the top of the dialog box.
Click on C++ Source file. Name
the file “BasicWindow” on the right hand side of the dialog box and press the
ok button.
3.
At
this point you should see a cursor blinking in the editor window. If not, click on the FileView tab in the
workspace window. Expand ( if necessary
) the source files folder. Double-click
on BasicWindow.cpp.
4.
This
is where you need to type all the necessary code for the BasicWindow.cpp
file. As with any C/C++ program, you
need a main function to run the program.
Type the following lines of code into this file.
#include
<FL/Fl.H>
#include <FL/Fl_Window.H>
int main()
{
Fl_Window b(20, 20, 400,
400,"Title for our window");
b.show();
return Fl::run();
}
5.
At
this point, save the file by either choosing File->Save or hitting Ctrl-S on
the keyboard.
6.
Now that
we have our file saved, we can compile our program. To compile the program, choose Build->Build [project name].exe
or press F7.
7.
Now,
to execute the program, choose Build-> Execute [project name].exe or press
Ctrl-F5 on the keyboard.
You should see two windows appear.
One window is the console window which will have an MS-DOS symbol and
the project path at the top. It will
have a blinking cursor in it as well.
The other window that will appear is your FLTK window that you have just
created. The console window is where
you will see all of your output from your program that you generate using cout
or printf. The FLTK window is your
Fl_Window that was just created. To close
the Fl_Window, either press the Esc key or press the X is the upper right corner
of the window.
Now that you can bring up a basic FLTK window, it is imperative that you
be able to handle certain events. Mouse
events are extremely important to handle because it is the most common input
device used to interface with GUIs.
1.
Create
a new C++ Header file called EventWindow.
2.
Type
the following lines code into this file, or copy them off of the demo web page.
( www.cs.wisc.edu/~pingelm/demo.html
)
Take note that the EventWindow class is inheriting from the Fl_Window
class. The Fl_Window class is the
widget that FLTK provides for us. Since
we know that we want to treat mouse events differently, we are going to want to
override the default code for the handle() method. This is what makes FLTK so powerful. We don’t have to spend our time writing windowing code. We simply want to add additional code that
specifies what to do when a mouse event occurs.
#ifndef
__EVENTWINDOW_H
#define
__EVENTWINDOW_H
#include
<FL/Fl_Window.H>
#include
<FL/Fl.H>
#include
<stdio.h>
class EventWindow:
public Fl_Window
{
private:
int handle_mouse(int event, int button, int x, int y);
public:
EventWindow(int width, int
height);
int handle(int e);
};
#endif
3.
Create
a new C++ Source file called EventWindow.
4.
Copy
the following lines of code into this file or copy them off of the demo web
page ( www.cs.wisc.edu/~pingelm/demo.html
)
Again, take note that the constructor for the EventWindow calls the
constructor for the Fl_Window. We are
not going to change anything about the window except for how it handles its
events.
#include
"EventWindow.h"
char * foo;
EventWindow::EventWindow(int
width, int height)
:Fl_Window(width,
height, "")
{
label("Demo Window for CS
559");
}
int
EventWindow::handle(int event)
{
switch (event) {
case FL_PUSH:
case FL_RELEASE:
case FL_DRAG:
case FL_MOVE:
return handle_mouse(event,Fl::event_button(),
Fl::event_x(),Fl::event_y());
case FL_FOCUS:
label
("Gained focus");
damage(1);
return
1;
case FL_UNFOCUS:
label
("Lost focus");
damage(1);
return
1;
default:
return
Fl_Window::handle(event);
};
}
int
EventWindow::handle_mouse(int event, int button, int x, int y) {
if (foo) delete [] foo;
foo = new char[100];
int ret = 0;
switch ( button ) {
case 1: // LMB
ret = 1;
// Based
on the action, print the action and
// coordinates
where it occurred.
if (
event == FL_PUSH ) {
sprintf(foo,"LMB
PUSH ( %d , %d )",x,y);
label(foo);
damage(1);
}
else if
(event == FL_DRAG ) {
sprintf(foo,"LMB
Drag ( %d , %d )",x,y);
label(foo);
damage(1);
}
else
if ( event == FL_RELEASE ) {
sprintf(foo,"LMB
Release ( %d , %d )",x,y);
label(foo);
damage(1);
}
break;
case 2: // MMB
ret = 1;
// Based
on the action, print the action and
//
coordinates where it occurred.
if ( event
== FL_PUSH ) {
sprintf(foo,"MMB
Push ( %d , %d )",x,y);
label(foo);
damage(1);
}
else if
(event == FL_DRAG ) {
sprintf(foo,"MMB
Drag ( %d , %d )",x,y);
label(foo);
damage(1);
}
else if
( event == FL_RELEASE ) {
sprintf(foo,"MMB Release (
%d , %d )",x,y);
label(foo);
damage(1);
}
break;
case 3: // RMB
ret = 1;
// Based
on the action, print the action and
//
coordinates where it occurred.
if (
event == FL_PUSH ) {
sprintf(foo,"RMB
Push ( %d , %d )",x,y);
label(foo);
damage(1);
}
else if
(event == FL_DRAG ) {
sprintf(foo,"RMB
Drag ( %d , %d )",x,y);
label(foo);
damage(1);
}
else if
( event == FL_RELEASE ) {
sprintf(foo,"RMB
Release ( %d , %d )",x,y);
label(foo);
damage(1);
}
break;
}
return ret;
}
5.
Delete
BasicWindow.cpp from the project workspace by selecting it in the workspace
window and pressing the Delete key.
Note, this does not delete the file from your directory, it only removes
it from the project.
6.
Create
a new C++ source file called EventWindowMain.
7.
Copy
the following lines of code into this file or get them off of the demo web page
( www.cs.wisc.edu/~pingelm/demo.html
).
#include
<FL/Fl.H>
#include
<FL/Fl_Window.H>
#include
"EventWindow.h"
int main()
{
EventWindow b(260, 260);
b.show();
return Fl::run();
}
Now, using the
previously mentioned methodology, build and run this application.
Watch the
label change as it corresponds to what you’re doing with the mouse. Try clicking on the window with each mouse
button. What happens as you drag the
mouse? What occurs as you minimize and
restore the window? Take a look at the
code. See if you can follow what is
occurring on the screen and how it is being accomplished in the code.
HANDLING KEYBOARD EVENTS
Another
useful way to obtain information from the user is via the keyboard. FLTK provides a pretty simple way to handle
keyboard events. We’ve already seen how
the handle function handles mouse events, now let’s take a look at how the handle
function may incorporate keyboard events as well.
int handle_key(int
event, int key);
case
FL_KEYBOARD: return handle_key(event,Fl::event_key());
int
EventWindow::handle_key(int event, int key) {
switch ( key ) {
case 'c': label ("letter c was depressed");
damage(1);
return 1;
default: label ("Nothing to do!");
damage(1);
printf("nothing
to do\n");
return 1;
}
}
At this
point you’ve seen how to handle events, and how to fire up a quick
interface. The one thing that remains
is the ability to add some basic components to your windows. So, let’s go through how to add a few
buttons to a window and register callbacks for those buttons.
// FLTK demo program
for CS559
// Fall, 2000, Mark
Pingel
#include
<FL/Fl.H>
#include
<FL/Fl_Window.H>
#include
<FL/Fl_Check_Button.H>
#include
<FL/Fl_Light_Button.H>
// Create pointers to
a check button and a light button
Fl_Check_Button*
check_b;
Fl_Light_Button*
light_b;
// Callback function
for the check button.
// Turn the label red
and change it to read Checked if the
// check button is
checked.
void
checkbutton_cb(Fl_Widget* w) {
Fl_Check_Button* flcb =
((Fl_Check_Button*)w);
if ( flcb->value() == 1 ) {
flcb->labelcolor(FL_RED);
flcb->label("Checked");
}
else {
flcb->labelcolor(FL_CYAN);
flcb->label("Check
Button");
}
flcb->damage(1);
flcb->parent()->redraw();
}
// Callback function
for the light button.
// Turn the label yellow
and change it to read Light On if the
// light button is
pressed. A yellow square will also
appear in
// the box to the
left of the label if selected
void
lightbutton_cb(Fl_Widget* w) {
Fl_Light_Button* fllb =
((Fl_Light_Button*)w);
if ( fllb->value() == 1 ) {
check_b->hide();
}
else {
check_b->show();
}
fllb->damage(1);
fllb->parent()->redraw();
}
int main(int argc,
char ** argv) {
// Create a window to add our
buttons to
Fl_Window* w = new
Fl_Window(190,80);
w->label("559 Demo
Window");
// Begin adding children to this
window
w->begin();
// Instantiate
the check button
// x , y ,
width, height, label
check_b = new
Fl_Check_Button(25,15,140,20,"Check Button");
// Instantiate
the light button
// x , y , width,
height, label
light_b = new
Fl_Light_Button(25,45,140,20,"Hide Check Button");
// Make all of
the default colors for the labels cyan
check_b->labelcolor(FL_CYAN);
light_b->labelcolor(FL_CYAN);
// Register the
callbacks for each of the buttons
check_b->callback(checkbutton_cb);
light_b->callback(lightbutton_cb);
// Stop adding children to this
window
w->end();
// Display the window
w->show();
// Run
return Fl::run();
}
Now, using
the code that is already there as a model, let’s add another button that
controls whether or not the Hide Check Button should be grayed out ( activated
) or not.
#include <FL/Fl_Round_Button.H>
is listed. So, at this point we
can go back to our code and add this line in the list of includes.
Fl_Round_Button*
round_b;
void
round_b_cb(Fl_Widget* w) {
}
Note: You can name the function anything you like. I generally try to name the callback
function something intuitive. Otherwise
it may become more difficult when you have complex interfaces with over fifty
widgets and you’re trying to match up a callback with a widget.
Therefore, our code should resemble:
if (
((Fl_Round_Button*)w)->value() == 1 ) {
}
else {
}
void
round_b_cb(Fl_Widget* w) {
if (
((Fl_Round_Button*)w)->value() == 1 ) {
light_b->activate();
}
else
{
light_b->deactivate();
}
w->damage(1);
w->parent()->redraw();
}
The damage(1) tells FLTK that the widget needs to be redrawn. The redraw() function tells FLTK that the
round button’s parent ( the window itself ) needs to be redrawn.
To create the button, we just need to specify a location on the window,
a width, a height, and a label.
round_b = new
Fl_Round_Button(25, 75, 140, 20, “Activate Light B”);
round_b->labelcolor(FL_CYAN);
round_b->callback(round_b_cb);
I strongly
recommend reading through some of the documentation on FLTK’s website
and playing around with the extra widgets.
Try adding some other widgets besides buttons.
Some things
to note:
Fl::event_button()
returns an integer corresponding to which mouse button was pressed.
1 - Left
mouse button
2 - Middle
mouse button
3 - Right
mouse button
Fl::event_key()
returns an integer corresponding to which key on the keyboard was pushed. The following constants define the non-ASCII
keys on the keyboard for the FL_KEYBOARD events:
FL_Button - A mouse button; use Fl_Button
+ n for mouse button n.
FL_BackSpace - The backspace key.
FL_Tab - The tab key.
FL_Enter - The enter key.
FL_Pause - The pause key.
FL_Scroll_Lock - The scroll lock key.
FL_Escape - The escape key.
FL_Home - The home key.
FL_Left - The left arrow key.
FL_Up - The up arrow key.
FL_Right - The right arrow key.
FL_Down - The down arrow key.
FL_Page_Up - The page-up key.
FL_Page_Down - The page-down key.
FL_End - The end key.
FL_Print - The print (or print-screen)
key.
FL_Insert - The insert key.
FL_Menu - The menu key.
FL_Num_Lock - The num lock key.
FL_KP - One of the keypad numbers; use
FL_KP + n for number n.
FL_KP_Enter - The enter key on the
keypad.
FL_F - One of the function keys; use FL_F
+ n for function key n.
FL_Shift_L - The lefthand shift key.
FL_Shift_R - The righthand shift key.
FL_Control_L - The lefthand control key.
FL_Control_R - The righthand control key.
FL_Caps_Lock - The caps lock key.
FL_Meta_L - The left meta/Windows key.
FL_Meta_R - The right meta/Windows key.
FL_Alt_L - The left alt key.
FL_Alt_R - The right alt key.
FL_Delete - The delete key.