參考內容:關於雙緩衝
我們看電視時,看到的螢幕稱為OSD層,也就是說,只有在OSD層上顯示映像我們才能看到。現在,我需要建立一個虛擬、看不見但是可以在上面畫圖(比如說畫點、線)的OSD層,我稱之為offscreen(背景緩衝區)。這個offscreen存在於記憶體中,我們在上面畫圖,這個offscreen上面的東西可以顯示在OSD層上,需要一個建立這個offscreen的函數,返回這個offscreen的控制代碼(整型指標)、寬度、高度、指向建立offscreen資料緩衝區的指標,該緩衝區是一個在函數外建立的offscreen的資料緩衝區,大小是offscreen的高度*寬度*每個像素點資料的大小。閃爍是圖形編程的一個常見問題。需要多重複雜繪製操作的圖形操作會導致呈現的映像閃爍或具有其他不可接受的外觀。雙緩衝的使用解決這些問題。雙緩衝使用記憶體緩衝區來解決由多重繪製操作造成的閃爍問題。當啟用雙緩衝時,所有繪製操作首先呈現到記憶體緩衝區,而不是螢幕上的繪圖圖面。所有繪製操作完成後,記憶體緩衝區直接複製到與其關聯的繪圖圖面。因為在螢幕上只執行一個圖形操作,所以消除了由複雜繪製操作造成的映像閃爍。
在Java swing中,繪製的原理如下:
update() -> paint(Graphics g) -> paintComponent(Graphics g)
它們是逐漸調用的,Java swing內建有雙緩衝,在paint(Graphics g)中。
假如我們的映像繪製在JPanel上,我們可以繼承JPanel,然後複寫裡面的paintComponent(Graphics g)和update方法。我們可以在paintComponent上繪製映像,然後調用paint方法就可以調用paintComponent方法繪製映像。
雙緩衝的實現:
複寫JPanel類中的update()方法,建立一個映像緩衝空間,然後把它的畫筆拿過來,用paint方法把要繪製的東西繪製上去。再一次性把映像顯示在JPanel控制項上。
我在這裡是用滑鼠畫線消除閃動的例子來說明雙緩衝的使用。
import java.awt.Canvas;import java.awt.Color;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Image;import java.awt.event.MouseEvent;import java.awt.event.MouseMotionAdapter;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.awt.image.BufferedImage;import javax.swing.JFrame;public class DrawTrail{ BufferedImage image = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); private DrawCanvas canvas = new DrawCanvas(); private int preX = -1; private int preY = -1; private Image offScreenImage; //圖形緩衝 public void init() { g.fillRect(0, 0, 1600, 1000); JFrame frame = new JFrame("測試畫出滑鼠的軌跡"); frame.setSize(600, 600); frame.add(canvas); frame.setLayout(null); canvas.setBounds(0, 0, 500, 500); frame.setVisible(true); canvas.addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseDragged(MouseEvent e) { if (preX > 0 && preY > 0) { g.setColor(Color.black); g.drawLine(preX, preY, e.getX(), e.getY()); } preX = e.getX(); preY = e.getY(); canvas.repaint(); } }); frame.addWindowListener(new WindowAdapter()//添加視窗關閉處理函數 { public void windowClosing(WindowEvent e) { System.exit(0); }}); } public static void main(String[] args) { DrawTrail dc = new DrawTrail(); dc.init(); } class DrawCanvas extends Canvas { private static final long serialVersionUID = 1L; @Override public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; g2.drawImage(image, 0, 0, null); } @Override public void update(Graphics g) { if(offScreenImage == null) offScreenImage = this.createImage(500, 500); //建立一個映像緩衝空間,這裡映像大小為800*600 Graphics gImage = offScreenImage.getGraphics(); //把它的畫筆拿過來,給gImage儲存著 paint(gImage); //將要畫的東西畫到映像緩衝空間去 g.drawImage(offScreenImage, 0, 0, null); //然後一次性顯示出來 } }}