雙緩衝在畫板程式中的應用(二) (轉)

amyz發表於2007-08-14
雙緩衝在畫板程式中的應用(二) (轉)[@more@]

/文 14E.T.

2.用雙緩衝實現各種圖形的繪製


在一個畫板中,應該能夠用畫筆繪製各種圖形,除了上一節實現的自由畫法(Freehand)外,還應該可以畫直線,長方體,橢圓等等.以繪製直線為例,我們都知道,只有在鬆開滑鼠鍵之後,直線才實實在在的顯示在了畫布上,而在拖拽滑鼠的過程中,直線在畫布中的顯示是隨著滑鼠的箭頭方位的變化而不斷的.體現在程式中,這是一個不斷擦除,顯示,再擦除,再顯示的過程.擦除的是箭頭上一個點和起點間的直線,顯示的是箭頭當前點和起點間的的直線.這個顯示的過程由update_buffer負責,而這個擦除的工作則和上一節出理重新整理一樣,由copy_from_offscreen_buf來完成.實際上,所謂擦除,也就是將畫板恢復到某一個原來的時刻.

這一個過程在下面一個修改後的拖拽操作的處理程式中完成:

public void mouseDragged(MouseEvent e){
  Graphics g = getGraphics();
  copy_from_offscreen_buf(g);
  x1=e.getX();
  y1=e.getY();
  update_buffer(g,new DrawItem(x0,y0,x1,y1));
  g.dispose();
}

注意,在該方法中,我們沒有對後臺緩衝進行更新,這是因為滑鼠在拖拽的時候,雖然畫板上會顯示線條,但是這條直線並沒有真正的畫下去.那麼在什麼時候應該對後臺緩衝更新呢?顯然,是在滑鼠鬆開的時候.我們需要在mouseReleased方法中做這個工作.

  public void mouseReleased(MouseEvent e){
  Graphics g = getGraphics();
  copy_from_offscreen_buf(g);
  x1=e.getX();
  y1=e.getY();
  update_buffer(g,new DrawItem(x0,y0,x1,y1));
  update_buffer(off_screen_gc,new DrawItem(x0,y0,x1,y1)); 
  g.dispose();
  }

可以看到,只有在滑鼠鬆開的時候,畫到畫板上的直線才最後確定了,我們才能夠將這一條線到緩衝區裡面去.

下面是升級後的完整的WhiteBoard.程式.

import java.awt.*;
import java.awt.event.*;

public class WhiteBoard extends Canvas implements MouseMotionListener,MouseListener{

  final static int DEFAULT_BOARDWIDTH=700;
  final static int DEFAULT_BOARDHEIGHT=400;
  int x0,y0,x1,y1;

  WhiteBoard(WBApplet WBApplet1){
  parent = WBApplet1;
  off_screen_buf =parent.createImage(DEFAULT_BOARDWIDTH,DEFAULT_BOARDHEIGHT);
  off_screen_gc = off_screen_buf.getGraphics();
  addMouseMotionListener(this);
  addMouseListener(this);
  draw_mode=2;
  }


  synchronized public void update_buffer(Graphics g,DrawItem data) {
  g.drawLine(data.x0,data.y0,data.x1,data.y1);
  }
 
  public void mouseMoved(MouseEvent e){} 
  public void mouseReleased(MouseEvent e){
   switch(draw_mode){
    case 2: 
  Graphics g = getGraphics();
  copy_from_offscreen_buf(g);
    x1=e.getX();
  y1=e.getY();
  update_buffer(g,new DrawItem(x0,y0,x1,y1));
  update_buffer(off_screen_gc,new DrawItem(x0,y0,x1,y1)); 
  g.dispose();
   } 
   
  }
  public void mouseEntered(MouseEvent e){}
  public void mouseExited(MouseEvent e){}
  public void mouseClicked(MouseEvent e){}
 
  public void mouseDragged(MouseEvent e){
  switch(draw_mode){
  case 1:
  x1=e.getX();
  y1=e.getY();
  Graphics g = getGraphics();
  update_buffer(g,new DrawItem(x0,y0,x1,y1));
  update_buffer(off_screen_gc,new DrawItem(x0,y0,x1,y1)); 
  g.dispose();
  x0=x1;
  y0=y1; 
  break;
  case 2: 
  Graphics g1 = getGraphics();
  copy_from_offscreen_buf(g1);
    x1=e.getX();
  y1=e.getY();
  update_buffer(g1,new DrawItem(x0,y0,x1,y1));
  g1.dispose();
  } 
  }
 
  public void mousePressed(MouseEvent e){
  x0 =e.getX();
  y0 =e.getY(); 
  } 


  public void paint(Graphics g){
  copy_from_offscreen_buf(g);
  } 

  void copy_from_offscreen_buf(Graphics g){
  if(g != null)
  g.drawImage(off_screen_buf, 0, 0, null);
  }
 

  private int draw_mode; 
  private Image off_screen_buf;
  private Graphics off_screen_gc;
  WBApplet parent;
 
}

class DrawItem{
  DrawItem(int x0,int y0,int x1,int y1){
  this.x0=x0;
  this.y0=y0;
  this.x1=x1;
  this.y1=y1;
 }
  int x0;
  int y0;
  int x1;
  int y1;
}

///:~

注意到,在這個程式裡面我們建立了一個新的私有變數draw_mode,用來繪圖的代號.在這裡,我們使用1來代表自由繪畫,2來代表畫直線.在構造中為draw_mode定義初值可以使我們對不同種類圖形繪製的很方便,在上面的程式中,我們定義的是2,如果賦值為1,則又回到自由繪畫的模式.事實上,我們應該在這樣的一個上把程式不斷的擴充和完善.


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-956275/,如需轉載,請註明出處,否則將追究法律責任。

相關文章