1. 程式人生 > >Java小程式之高階畫板重繪篇II

Java小程式之高階畫板重繪篇II

   Java自動轉型和多型

自動轉型:子類的物件自動轉型為父類的型別

注意:如果轉型後的物件呼叫方法,這個方法如果子類重寫了,則執行的是重寫後的,如果沒有重寫,則呼叫的是父類的

多型:多個同一個型別的物件,呼叫同一個方法,執行的過程不一樣,多型的前提是有繼承關係並且子類中重寫了父類當中的某些方法;

重繪思路:

1、抽象出父類Shape以及父類的draw方法;

2、Line類,Rect類,Oval類繼承父類

3、重寫父類的draw方法,實現不同的子類畫出不同的圖形;

4、在DrawListener中,根據選擇畫筆的不同,先產生相應的物件,利用物件的draw方法,實現不同圖形的畫法;

5、把產生的物件裝入容器物件;

6、在panelcenterchild中的paint方法中,將容器中的物件一個一個取出來,進行圖形的重繪;

原始碼:

抽象父類:Shape類

package com.huaxin.zhou1;

import java.awt.Color;
import java.awt.Graphics2D;

//抽象父類
public abstract class Shape {
	
	public  int x1,y1,x2,y2;//繪製圖形的座標
	public Color color;//畫筆顏色
	public int width;//畫筆粗細
	//抽象的Draw方法
	public abstract void Draw(Graphics2D g);

}

子類1:Line類
package com.huaxin.zhou1;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;

public class Line extends Shape{
	
	public Line(){
		
	}
	//子類建構函式
	public Line(int x1,int y1,int x2,int y2,Color color,int width){
		this.x1=x1;
		this.y1=y1;
		this.x2=x2;
		this.y2=y2;
		this.color=color;
		this.width=width;
	}
  //重寫父類的Draw方法,實現直線的繪製
	public void Draw(Graphics2D g) {
		g.setColor(this.color);
		g.setStroke(new BasicStroke(width));
		g.drawLine(x1, y1, x2, y2);
	}

}

子類2:Rect類
package com.huaxin.zhou1;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;

public class Rect extends Shape{
	
	public Rect(){
		
	}
	//矩形的構造方法
	public Rect(int x1,int y1,int x2,int y2,Color color,int width){
		this.x1=x1;
		this.y1=y1;
		this.x2=x2;
		this.y2=y2;
		this.color=color;
		this.width=width;
	}

    //重寫父類的Draw方法,實現矩形的繪製
	public void Draw(Graphics2D g) {
		g.setColor(this.color);
		g.setStroke(new BasicStroke(width));
		g.drawRect(x1, y1, x2, y2);
	}

}

子類3:Oval類
package com.huaxin.zhou1;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;

public class Oval extends Shape{
	
	public Oval(){
		
	}
	
	public Oval(int x1,int y1,int x2,int y2,Color color ,int width){
		this.x1=x1;
		this.y1=y1;
		this.x2=x2;
		this.y2=y2;
		this.color=color;
		this.width=width;
	}


	public void Draw(Graphics2D g) {
		g.setColor(this.color);
		g.setStroke(new BasicStroke(width));
		g.drawOval(x1, y1, x2, y2);
	}

	
}

子類4:RoundRect類
package com.huaxin.zhou1;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;

public class RoundRect extends Shape{
	
	//子類新增屬性,圓角矩形的角的彎曲程度
	public int arcWidth,arcHeight;
	

	public RoundRect(){
		
	}
	
	public RoundRect(int x1,int y1,int x2,int y2,int i,int j,Color color ,int width){
		this.x1=x1;
		this.y1=y1;
		this.x2=x2;
		this.y2=y2;
		this.arcWidth=i;
		this.arcHeight=j;
		this.color=color;
		this.width=width;
	}
    
	public void Draw(Graphics2D g) {
		g.setColor(this.color);
		g.setStroke(new BasicStroke(width));
		g.drawRoundRect(x1, y1, x2, y2, this.arcWidth, this.arcHeight);
	}

}

DrawBorder類:注意在這個類中新增容器,並把容器地址傳給DrawListener;panelcenterchild中重寫paint方法,重繪圖形;
package com.huaxin.zhou1;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.BevelBorder;

public class DrawBorder extends JFrame{
	
	//宣告顏色屬性,並賦預設值
	public Color c=Color.RED;
	//按鈕屬性,便於其他類訪問
	public JButton  bt ;
	
	//容器
	ArrayList list = new ArrayList();

	public void initFrame(){
		
		//設定窗體相關屬性
		this.setSize(600,500);
		this.setTitle("我的畫板");
		this.setDefaultCloseOperation(3);
		this.setLocationRelativeTo(null);
		
		//窗體新增主面板
		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
		this.add(panel);
		
		
		JPanel panelcenter = new JPanel(){
			public void paint(Graphics g1) {
				Graphics2D	g=(Graphics2D)g1;
				super.paint(g);
				for (int i = 0; i <list.size(); i++) {
					Shape shape =(Shape)list.get(i);
					shape.Draw(g);
				}
			}
		};
	    panelcenter.setBackground(Color.white);
		panel.add(panelcenter);
		
		//主面板新增左面板
		JPanel panelleft = new JPanel();
		panelleft.setPreferredSize(new Dimension(50,0));
		panelleft.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
		panelleft.setBackground(new Color(235,233,238));
		panel.add(panelleft,BorderLayout.WEST);
		
		//面板中新增按鈕
		//按鈕歸類,統一管路
		ButtonGroup bg = new ButtonGroup();
		for(int i=0;i<16;i++){
			JRadioButton jrb = new JRadioButton();
			
			//給按鈕新增圖片
			ImageIcon img1  = new ImageIcon("images/draw"+i+".jpg");
			ImageIcon img2  = new ImageIcon("images/draw"+i+"-1.jpg");
			ImageIcon img3  = new ImageIcon("images/draw"+i+"-2.jpg");
			ImageIcon img4  = new ImageIcon("images/draw"+i+"-3.jpg");
			jrb.setIcon(img1);
			jrb.setRolloverIcon(img2);
			jrb.setPressedIcon(img3);
			jrb.setSelectedIcon(img4);
			jrb.setBorder(null);
			//設定預設選中的按鈕
			if(i==10){
				jrb.setSelected(true);
			}
			jrb.setActionCommand("pic"+i);
			
			bg.add(jrb);
			panelleft.add(jrb);
		}
		
		//主面板新增下方面板
		JPanel paneldown =new JPanel();
		paneldown.setPreferredSize(new Dimension(0,60));
		paneldown.setLayout(null);
		paneldown.setBackground(Color.gray);
		panel.add(paneldown, BorderLayout.SOUTH);
		
		//下方面板新增子面板
		JPanel paneldownchild = new JPanel();
		paneldownchild.setBackground(Color.cyan);
		paneldownchild.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
		paneldownchild.setBounds(10,10,280,40);
		paneldown.add(paneldownchild);
		
		//按鈕特效
		BevelBorder bb = new BevelBorder(0, Color.gray,Color.white);
		BevelBorder bb1 = new BevelBorder(1, Color.gray,Color.white);
		
		JPanel left = new JPanel();
		left.setBackground(Color.white);
		left.setLayout(null);
		left.setBorder(bb);
		left.setPreferredSize(new Dimension(40,40));
		
		//左面板中的兩棵顏色按鈕
	    bt = new JButton();
		bt.setBounds(5, 5, 20, 20);
		bt.setBorder(bb1);
		bt.setBackground(Color.black);
		bt.setSize(20,20);
		JButton bt1 = new JButton();
		bt1.setBorder(bb1);
		bt1.setBounds(15,15,20,20);
		left.add(bt);
		left.add(bt1);
		
        //右面板
		JPanel right = new JPanel();
		right.setBackground(Color.BLUE);
		right.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
		right.setPreferredSize(new Dimension(240,40));
		
		paneldownchild.add(left);
		paneldownchild.add(right);
		
		//給右面板的顏色按鈕天新增監聽器,注意傳遞this物件
		ButtonListener bl =new ButtonListener(this);
		//顏色陣列,用來設定按鈕的背景顏色
		Color []colors = {new Color(0,56,67),new Color(89,3,14),new Color(189,3,14)
				,new Color(89,93,14),new Color(89,113,14),new Color(89,73,14)
				,new Color(89,3,14),new Color(89,3,14),new Color(29,83,14)
				,new Color(89,3,184),new Color(189,233,14),new Color(89,253,14)
				,new Color(89,93,14),new Color(89,89,94),new Color(1,3,14)
				,new Color(9,83,94),new Color(89,178,147),new Color(9,33,164)
				,new Color(34,23,14),new Color(89,173,154),new Color(8,193,194)
				,new Color(9,253,76),new Color(89,240,104),new Color(199,73,4)};
		
		//迴圈新增24個顏色按鈕
		for(int i=0;i<24;i++){
			JButton bt3 = new JButton();
		    Color c=new Color(i*10,30-i,i*7+50);
		    bt3.setBackground(colors[i]);
		    bt3.setPreferredSize(new Dimension(20,20));
		    bt3.setBorder(bb);
		    bt3.addActionListener(bl);
			right.add(bt3);
		}
		
		this.setVisible(true);
		
		//畫筆必須在setVisible後才能拿
		Graphics g=panelcenter.getGraphics();
		
		//傳遞畫筆,按鈕組管理物件,以及this物件
		DrawListener dl =new DrawListener(g,bg,this,list);
		
		//新增普通滑鼠監聽器
		panelcenter.addMouseListener(dl);
		
		//新增滑鼠拖動監聽器
		panelcenter.addMouseMotionListener(dl);
			
	}
}

DrawListener類:根據圖形的不同選擇,利用對臺先產生不同的物件,再利用物件的Draw方法,繪製圖形,並將該圖形物件那個新增到容器中
package com.huaxin.zhou1;

import java.awt.AWTException;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;


public class DrawListener implements MouseListener,MouseMotionListener{
	
	public Graphics2D g;
	public int x1,y1,x2,y2,ox,oy,x3,y3;
	public ButtonGroup bg;
	public String command;
	public Color color;
	public DrawBorder db;
	public ArrayList list;
	public boolean flag=true;
	
	public static final  Stroke s1 = new BasicStroke(1);
	public static final  Stroke s2 = new BasicStroke(10);
	public static final  Stroke s3 = new BasicStroke(15);
	
	public Random r =new Random();
	//建構函式1
	public DrawListener(Graphics g1){
		g=(Graphics2D)g1;
	}
	
	//建構函式2
	public DrawListener(Graphics g2, ButtonGroup bg2) {
		g=(Graphics2D)g2;
		bg=bg2;
	}

    //建構函式3
	public DrawListener(Graphics g2, ButtonGroup bg2, DrawBorder db1,ArrayList list) {
		g=(Graphics2D)g2;
		bg=bg2;
		db=db1;
		this.list=list;
	}

    //滑鼠按下事件監聽
	public void mousePressed(MouseEvent e) {
		//獲取滑鼠按下點的座標
		x1=e.getX();
		y1=e.getY();
		
	
		
		//判斷選擇的是左面板中的那個按鈕被選中(前面已經設定每個按鈕的名稱了)  
        ButtonModel bm=bg.getSelection();//拿到按鈕組中被選中的按鈕  
        command=bm.getActionCommand();//拿到選中按鈕的名字  
       
	}

	public void mouseReleased(MouseEvent e) {  
        //獲取滑鼠釋放的座標  
        x2=e.getX();  
        y2=e.getY();  
        
        
        //如果選中的是繪製直線的按鈕,那麼根據滑鼠按下點的座標和釋放點的左邊繪製直線(兩點確定一條直線)  
        if("pic10".equals(command))  
        {  
        	Shape line = new Line(x1, y1, x2, y2,g.getColor(),1);
        	line.Draw(g);
        	list.add(line);
        }//同理選中的是矩形按鈕,那麼繪製矩形(這裡有繪製矩形的糾正,不糾正的話從右下角往左上角方向繪製矩形會出現問題,參看後面難點解析)  
        else if("pic12".equals(command)){  
        	Shape rect = new Rect(Math.min(x2, x1),Math.min(y2, y1), Math.abs(x2-x1),Math.abs(y1-y2),g.getColor(),1);
        	rect.Draw(g);
        	list.add(rect);
        }//繪製橢圓  
        else if("pic14".equals(command)){  
        	Shape oval = new Oval(Math.min(x2, x1),Math.min(y2, y1), Math.abs(x2-x1),Math.abs(y1-y2),g.getColor(),1);
        	oval.Draw(g);
        	list.add(oval);
        } else if("pic15".equals(command)){
        	Shape roundrect = new RoundRect(Math.min(x2, x1),Math.min(y2, y1), Math.abs(x2-x1),Math.abs(y1-y2),40,40,g.getColor(),1);
        	roundrect.Draw(g);
        	list.add(roundrect);
        }//繪製曲線
        else if("pic13".equals(command)){
        	
        	//第一次畫直線,設定標誌
        	if(flag){
        		Shape line = new Line(x1, y1, x2, y2,g.getColor(),1);
            	line.Draw(g);
            	list.add(line);
                flag=false;
              //記錄這次滑鼠釋放的座標,作為下次繪製直線的起點
                x3=x2;
                y3=y2;
                //記錄第一點選的座標,繪製封閉的曲線
                ox=x1;
                oy=y1;
        	}
        	else{
        		Shape line = new Line(x3, y3, x2, y2,g.getColor(),1);
             	line.Draw(g);
             	list.add(line);
        		  //記錄上次滑鼠釋放的座標
                 x3=x2;
                 y3=y2; 
        	}
        }
        //取色功能
        else if("pic4".equals(command)){
        	
        	//拿到相對面板的那個座標
    		int x=e.getXOnScreen();
    		int y=e.getYOnScreen();
    		
    		try {
    			
				Robot robot = new Robot();//Robot類的使用
				
				//拿到座標點的那個矩形
			    Rectangle rect = new Rectangle(x,y,1,1);
			    //生成該矩形的緩衝圖片
				BufferedImage bi =robot.createScreenCapture(rect);
				//得到圖片的背景顏色
				int  c =bi.getRGB(0, 0);
				//將該顏色進行封裝
				Color color = new Color(c);
				//將取色筆取來的圖片設定成畫筆的顏色
				db.c=color;
			} catch (AWTException e1) {
				e1.printStackTrace();
			}
    	}
          
    }  

	public void mouseClicked(MouseEvent e) {
		//多邊形圖形雙擊封閉
		int count =e.getClickCount();
		if(count==2 && "pic13".equals(command)){
			Shape line = new Line(ox, oy, x2, y2,g.getColor(),1);
         	line.Draw(g);
         	list.add(line);
		
			flag=true;
		}
	}

	public void mouseEntered(MouseEvent e) {
		    color=db.c;//設定畫筆顏色  
			g.setColor(color);
			g.setStroke(s1);
	}

	public void mouseExited(MouseEvent e) {
		
	}

	public void mouseDragged(MouseEvent e) {
		
		int x=e.getX();
		int y=e.getY();
		
		//畫筆功能
		if("pic6".equals(command)){
			
			Shape line = new Line(x1, y1, x, y,g.getColor(),1);
         	line.Draw(g);
         	list.add(line);
			x1=x;
			y1=y;
		}
		//橡皮擦功能
		else if("pic2".equals(command)){
			db.c=Color.white;
			g.setColor(db.c);
			g.setStroke(s3);
			
			Shape line = new Line(x1, y1, x, y,g.getColor(),15);
         	line.Draw(g);
         	list.add(line);
			
			x1=x;
			y1=y;
		}
		//刷子功能
		else if("pic7".equals(command)){
			g.setStroke(s2);//設定畫筆 粗細
			
			Shape line = new Line(x1, y1, x, y,g.getColor(),10);
         	line.Draw(g);
         	list.add(line);
         	
			x1=x;
			y1=y;
		}
		//噴桶功能
		else if("pic8".equals(command)){
			//隨機產生30個-15到15之間的整數
			for (int i = 0; i < 30; i++) {
				int xp=r.nextInt(31)-15;
				int yp=r.nextInt(31)-15;
				//在x,y附件繪製原點
				
				Shape line = new Line(x+xp, y+yp, x+xp, y+yp,g.getColor(),1);
	         	line.Draw(g);
	         	list.add(line);
			}
			
		}
		
		
	}

	public void mouseMoved(MouseEvent e) {
		
	}

	

}

測試類:
package com.huaxin.zhou1;

public class Test {
   
	//測試函式
	public static void main(String[] args) {
		DrawBorder db = new DrawBorder();
		db.initFrame();
	}
}
執行結果:

最小化後再最大化,圖形還是在的喲!

總結:

1、Java小專案之高階畫板基本完全竣工,用到的知識有繼承,重寫,多型,建構函式,物件傳遞,容器的使用等;

2、通過自己完成畫板專案,對Java中的知識加深了理解,同時自己的動手能力得到加強;

3、個人經驗,做東西一定首先要理解思路,思路要非常清楚,這樣寫東西才能知道怎麼寫,要一步一步來,不要急於求成;當然思路是建立在你對知識有一定的理解的基礎上的;

4、一定要多動手實踐,簡單的程式碼也要敲上兩三遍,深刻了解其中的原理;

5、學路漫漫,一起共勉!

畫板左邊的按鈕圖片資源以上傳,在我的資源中!歡迎下載使用!