【翻譯自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的幕後緩衝區當前有一個合適的圖形上下文環境【??】。