1. 程式人生 > >影象化介面paint,repaint方法的總結

影象化介面paint,repaint方法的總結

JAVA 畫圖中出現的paint()函式

問題:小弟剛學JAVA,有一個問題。以下是一段JAVA程式碼,它彈出了一個視窗,並在視窗上使用paint()畫出矩形、橢圓、扇面等圖形。但鑑於paint()並不在main()中執行,所以它會一次畫完。現在我想讓畫圖行為受使用者控制,比如說,開始只有一個空白視窗。當用戶輸入1,畫出矩形。使用者輸入2,擦掉矩形。使用者輸入3,畫出橢圓。等等等等。

所以小弟應該如何做?有什麼思路?需要什麼東西?

案例程式碼:

import java.awt.*; 
import javax.swing.*;

public class Test extends JFrame { 
  public static void main(String[] args){
    Test sl = new Test();
    sl.update();
  }
 Test(){
    super("Sample");
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    setSize(600,600);
    setVisible(true);
  }
  public void update(){
    repaint();
  }
  public void paint(Graphics g) { 
     g.setColor(Color.black);     
     //有角矩形,起始點(10,30),寬80,高50
     g.drawRect(10,30,80,50);     
     //圓角矩形,起始點(110,30),寬80,高50,角(a=20,b=10)
     g.drawRoundRect(110,30,80,50,20,10);
     //橢圓,圓心(110,90)、a=80,b=50       
     g.drawOval(110,90,80,50); 
     //一條弧,圓心(219,30)、a=80,b=50 角度在0-90之間
     g.drawArc(210,30,80,50,0,90);
     //扇面,圓心(219,90)、a=80,b=50 角度在0-90之間
     g.fillArc(210,90,80,50,0,90);
  }
}

在俄羅斯方塊的程式碼中,我們也看到了一個public void paint(Graphics g)函式,似乎這個函式沒有被任何東西呼叫,並且還有一個相關聯的repeat方法,程式碼見下面的:

public void paint(Graphics g){
		g.drawImage(background, 0, 0, null);//使用this 作為觀察者
		g.translate(15, 15);//平移繪圖座標系
		paintTetromino(g);//繪製正在下落的方塊
		paintWall(g);//畫牆
		paintNextOne(g);
		paintScore(g);
	}

一,我們先執行第一個Test程式,得到的影象是:

在這裡插入圖片描述 我們可以看到paint方法是被呼叫了的。

首先paint方法,並不僅是JPanel的方法,而是繼承自JComponent的方法,該方法說明如下:
/**
     * Invoked by Swing to draw components
     * Applications should not invoke <code>paint</code> directly,
     * but should instead use the <code>repaint</code> method to
     * schedule the component for redrawing.
     * <p>
     * This method actually delegates the work of painting to three
     * protected methods: <code>paintComponent</code>,
     * <code>paintBorder</code>,
     * and <code>paintChildren</code>.  They're called in the order
     * listed to ensure that children appear on top of component itself.
     * Generally speaking, the component and its children should not
     * paint in the insets area allocated to the border. Subclasses can
     * just override this method, as always.  A subclass that just
     * wants to specialize the UI (look and feel) delegate's
     * <code>paint</code> method should just override
     * <code>paintComponent</code>.
     *
     * @param g  the <code>Graphics</code> context in which to paint
     * @see #paintComponent
     * @see #paintBorder
     * @see #paintChildren
     * @see #getComponentGraphics
     * @see #repaint
     */
--------------------- 
原文:https://blog.csdn.net/tanjun592/article/details/54926041 

這個方法是被swing呼叫來畫元件的,應用不應該直接呼叫paint,而應該呼叫repaint。paint這個方法實際上代表了三個protected的方法。 *paintComponent,paintBorder,paintChildren. *裡面一次呼叫者三種方法來確保…(略)

重要的是子類通常要重寫這個方法,來定製special特殊的圖形元件

其次,那麼為什麼不應該直接呼叫paint而應該呼叫repaint呢?查了很多資料,有一個說的很簡單,直接。
  • repaint()是重要概念,它是在圖形執行緒後追加一段重繪操作,是安全的!是系統真正呼叫的重繪!所以如果你需要某個部件重新整理一下介面,記得呼叫repaint(),千萬不要直接呼叫paint()!
  • Graphics是一個抽象類,其實現大都是平臺相關的,所以不容易自己建立一個graphics例項。一般graphics的例項會由依照你所在的桌面環境給出。
最後, repaint裡面間接呼叫了paint方法。但是是如何間接呼叫的呢?repaint方法裡面是否new了一個graphics物件呢然後傳給paint呢?

在這裡插入圖片描述

二,程式設計師使用過程:

所以做一個圖形元件的基本思路可以總結為以下過程: 選擇適合的基本圖形元件 -> 繼承它 -> 重寫paint等方法->在需要重新整理圖形的時候呼叫repaint等方法! 至於Graphics,先假設它存在,因為真正的Graphics例項只有當程式在jvm上跑的時候才會建立。 在這裡插入圖片描述 俄羅斯方塊中使用此技術的部分程式碼:

public class Tetris extends JPanel{
	public static void main(String[] args) {
		JFrame frame = new JFrame();
		Tetris tetris = new Tetris();
		frame.add(tetris);
		frame.setSize(525, 590);
		frame.setUndecorated(false);//true去掉視窗框!
		frame.setTitle("俄羅斯方塊");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//Location 位置 RelativeTo相對於 
		frame.setLocationRelativeTo(null);//使當前視窗居中
		frame.setVisible(true);
		tetris.action();
	}
		public void action(){
		//tetromino = Tetromino.randomTetromino();
		//nextOne = Tetromino.randomTetromino();
		//wall[19][2] = new Cell(19,2,Tetris.T);
		startAction();
		repaint();
		KeyAdapter l = new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				int key = e.getKeyCode();
				if(key == KeyEvent.VK_Q){
					System.exit(0);//退出當前的Java程序
				}
				if(gameOver){
					if(key==KeyEvent.VK_S){
						startAction();
					}
					return;
				}
				//如果暫停並且按鍵是[C]就繼續動作
				if(pause){//pause = false
					if(key==KeyEvent.VK_C){	continueAction();	}
					return;
				}
				//否則處理其它按鍵
				switch(key){
				case KeyEvent.VK_RIGHT: moveRightAction(); break;
				case KeyEvent.VK_LEFT: moveLeftAction(); break;
				case KeyEvent.VK_DOWN: softDropAction() ; break;
				case KeyEvent.VK_UP: rotateRightAction() ; break;
				case KeyEvent.VK_Z: rotateLeftAction() ; break;
				case KeyEvent.VK_SPACE: hardDropAction() ; break;
				case KeyEvent.VK_P: pauseAction() ; break;
				}
				repaint();
			}
		};
		this.requestFocus();
		this.addKeyListener(l);
	}
   public void paint(Graphics g){
		g.drawImage(background, 0, 0, null);//使用this 作為觀察者
		g.translate(15, 15);//平移繪圖座標系
		paintTetromino(g);//繪製正在下落的方塊
		paintWall(g);//畫牆
		paintNextOne(g);
		paintScore(g);
	}
	

可以看到,main方法中呼叫了action(),而action()方法中多次使用repaint()方法進行頁面重新整理。 在paint()方法中,實現具體的畫圖操作,可以看到都是使用Graphics的相關函式,下面列舉下其方法

  • g.drawImage(background, 0, 0, null)載入影象,畫出影象
  • g.translate(15, 15);//平移繪圖座標系
  • g.setColor(new Color(FONT_COLOR))設定顏色;
  • g.setFont(font);設定字串的字型
  • g.drawString(str, x, y)畫字串

應該注意的是,這裡面沒有多少其他元件插入的情況,完全是自己造的,從最基本的開始。