【翻译自fltk_tutorial.pdf第16部分】
part16:处理鼠标事件第二部分
这个例子有点像绘图程序。当你按下鼠标并拖动时,一条线就会随着鼠标移动绘出来。当点击左键时会连接下一次的点击位置绘出一条线,当点击右键时就会绘出一个矩形。

为渐进的绘图,最好在一个幕后缓冲区中绘制然后在调用draw函数时,将缓冲区复制到屏幕上。因为fltk不会存储屏幕内容所以当窗口变形和恢复时,所有的内容将被清除,幕后缓冲区的内容将会一直存在。这个例子就是使用渐进绘图,并且使用了幕后缓冲区。
#pragma comment(lib, "fltk.lib")
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "comctl32.lib")
#pragma comment(linker, "/NODEFAULTLIB:LIBCMTD.lib")
#include <stdio.h>
#include <Fl/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <Fl/Fl_Box.H>
#include <Fl/fl_draw.H>
#include <fl/x.H>
#define window_size 400
static Fl_Double_Window *main_window = 0; // the main app window
static Fl_Offscreen offscreen_buffer = 0; // the offscreen surface
/*****************************************************************************/
/* This class provides a view to copy the offscreen surface to */
class canvas : public Fl_Box
{
void draw();
int handle(int event);
public:
canvas(int x, int y, int w, int h);
};
/*****************************************************************************/
/* Constructor */
canvas::canvas(int x, int y, int w, int h) : Fl_Box(x,y,w,h)
{
} // Constructor
/*****************************************************************************/
void canvas::draw()
{
if(offscreen_buffer)
{ // offscreen exists
// blit the required view from the offscreen onto the box
fl_copy_offscreen(x(), y(), w(), h(), offscreen_buffer, 0,0);
}
else
{ // create the offscreen
main_window->make_current(); //ensures suitable graphic context
offscreen_buffer = fl_create_offscreen( w(), h() );
if(!offscreen_buffer)
{
fprintf(stderr,"Failed buffer creation");
exit(1);
}
fl_begin_offscreen(offscreen_buffer); /* Open the offscreen context */
fl_color(FL_WHITE);
fl_rectf(0, 0, w(), h() );
fl_end_offscreen(); /* close the offscreen context */
/* init screen with offscreen buffer */
fl_copy_offscreen(x(), y(), w(), h(), offscreen_buffer, 0,0);
}
} // draw method
/*****************************************************************************/
int canvas::handle(int event)
{
static char labeltext[100];
int button,x,y;
int retvalue = 0;
static int x_old,y_old;
static int push1st=0;
if (!offscreen_buffer) return 1;
retvalue = Fl_Box::handle(event);
switch (event)
{
case FL_PUSH:
case FL_DRAG:
button = Fl::event_button();
x = Fl::event_x();
y = Fl::event_y();
};
switch ( button )
{
case 1: // Left button
sprintf(labeltext,"Last mouse button= Left | Mouse at %d,%d now",x,y);
window()->label(labeltext);
retvalue = 1;
break;
case 3: // Right button
sprintf(labeltext,"Last mouse button= Right | Mouse at %d,%d now",x,y);
window()->label(labeltext);
retvalue = 1;
break;
}
switch(event)
{
case FL_PUSH:
if (push1st == 0)
{
x_old = x;
y_old = y;
push1st = 1;
break;
}
else
{
push1st = 0;
/* Open the offscreen context for drawing */
fl_begin_offscreen(offscreen_buffer);
if (button==1){ //left mouse button
fl_color(FL_RED);
fl_line(x_old,y_old,x,y);
} else { //right mouse button
fl_draw_box(FL_BORDER_FRAME,x_old,y_old,(x-x_old),
(y-y_old),FL_BLUE);
}
fl_end_offscreen(); /* close the offscreen context */
redraw();
}
case FL_DRAG:
{
push1st=0; //clear if dragging
/* Open the offscreen context for drawing */
fl_begin_offscreen(offscreen_buffer);
fl_color(FL_BLACK);
fl_point(x,y);
fl_end_offscreen(); // close the offscreen context
redraw();}
break;
default:
redraw();
break;
}
return retvalue;
} // handle
/*****************************************************************************/
int main (int argc, char **argv)
{
main_window = new Fl_Double_Window(window_size, window_size, "Drawing with mouse example");
main_window->begin();
// a view of the offscreen, inside the main window
static canvas *os_box = new canvas(5,5,(window_size-10),(window_size-10));
main_window->end();
main_window->resizable(os_box);
main_window->show(argc, argv);
return Fl::run();
} // main
【例子在VC6.0,使用FLTK1.1.10测试通过】
例子中定义了一个叫做canvas的Fl_Box子类新窗口类。定义了用来绘图的区域。在main函数中,这个canvas类的一个新的对象被创建作为main_window的子构件。
类canvas同时还定义了handle函数重载了Fl_Widgets::handle()虚函数。所有的事件将被FLTK发送到canvas的handle函数中。函数检查FL_PUSH和FL_DRAG两个不同的鼠标事件并且返回1来指示FLTK它们已经被这个函数处理过了。两个事件中收到任意一个,函数就会在窗口的标题中指示是哪一个鼠标键被按下了并且显示当前鼠标的位置。
如果是FL_DRAG事件,则将在当前位置绘出一点,如果是FL_PUSH键,将会保存鼠标位置,当第二次FL_PUSH事件时,根据是左键还是右键点击会绘制不同图形。如果是左键点击,则绘制一条连接上次点击位置和现在点击位置的直线。如果是右键点击,则绘制出的是一个矩形而不是直线。对幕后缓冲区的绘制开始于fl_begin_offscree(),结束于fl_end_offscreen()。
draw函数只需要将幕后缓冲区复制到屏幕。当第一次调用draw函数时,它将使用fl_create_offscreen分配幕后缓冲区,然后使用fl_rectf()清除缓冲区为白色。当缓冲区绘制到屏幕之后会将绘制区域绘制成白色。仅仅需要确认基于main_window的幕后缓冲区当前有一个合适的图形上下文环境【??】。