在此之前,我們已經實現專案的第二步,處理了每一張圖的顏色,我們讓小人的顏色是黑色,背景整體調整爲白色。本小節要做的就是在這些圖片上進行繪畫火柴人。因爲我們繪畫水平有限,我們希望在原圖片的輪廓上進行繪畫。
我們要想在已有的圖片上進行火柴人繪畫,首先得有繪畫的圖形介面。可以使用java中的swing組建來實現。
談到Java的圖形介面程程,指的就是GUI(圖形用戶介面)。Graphical User Interface,用圖形的方式,來顯示計算機操作的介面。
Java爲GUI提供的物件都在java.awt和javax.swing兩個包中。
相對於AWT而言Swing包中提供了更多的豐富的、快捷的、強大的GUI元件,而且這些元件都是java語言編寫而成,因此Swing不依賴本地平臺,可以真正做到跨平臺執行。通常而言我們把AWT稱之爲重量級元件,Swing稱之爲輕量級軟體,一般而言Swing元件都是在AWT元件名稱前加J。
JFrame 用來設計類似於 Windows 系統中視窗形式的介面。JFrame 是 Swing 元件的頂層容器,該類繼承了 AWT 的 Frame 類,支援 Swing 體系結構的高階 GUI 屬性。
在Swing元件中最常見的就是JFrame,他和Frame一樣是一個獨立存在的頂級視窗,不能放置在其他容器中,JFrame支援所有視窗的操作,例如視窗最小化,設定視窗大小。
JFrame():構造一個初始時不可見的新表單。
JFrame(String title):建立一個具有 title 指定標題的不可見新表單。
範例程式碼:
package qf.day05.demo;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
/**
* 建立圖形介面程式的思路:
*
* step1:建立frame表單,JFrame
*
* step2:對表單進行基本的設定:
* 大小,位置,佈局等等,標題。。。
*
* step3:定義裏面的元件:
* 按鈕,文字。。。---->JPanel
*
* step4:通過add()方法,將這些元件,新增到表單中。
*
* step5:讓表單顯示:setVisible(true)
*
* @author ruby
*
*/
public class Demo01_JFrame {
public static void main(String[] args) {
//1.建立frame表單
JFrame frame =new JFrame();
//2.設定表單
frame.setSize(400, 200);//視窗的大小,畫素
frame.setLocation(300, 500);
//frame.setBounds(300, 500, 400, 200);
frame.setTitle("我的第一個GUI程式,哈哈哈哈");//設定標題
frame.setLayout(new FlowLayout());//設定佈局
//3.擺放個按鈕
JButton button = new JButton("我是一個按鈕");
//將這個按鈕放在frame上
frame.add(button);
JTextField textField =new JTextField("haha",30);
frame.add(textField);
//設定表單可見
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//通過點選按鈕可以直接關閉程式
}
}
執行結果如下:
JPanel 是一種中間層容器,它能容納元件並將元件組合在一起,但它本身必須新增到其他容器中使用。JPanel 類的構造方法如下。
JPanel():使用預設的佈局管理器建立新面板,預設的佈局管理器爲 FlowLayout。
JPanel(LayoutManagerLayout layout):建立指定佈局管理器的 JPanel 物件。
範例程式碼:
package qf.day05.demo;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Demo02_JPanel {
public static void main(String[] args) {
JFrame frame = new JFrame("王二狗的程式");
frame.setLayout(new FlowLayout());
frame.setSize(520,700);
JPanel panel = new JPanel();//建立面板
panel.setPreferredSize(new Dimension(400, 300));//設定面板的寬和高
panel.setBackground(Color.BLUE);
JButton btn1 = new JButton("按鈕1");
JButton btn2 = new JButton("按鈕2");
JButton btn3 = new JButton("按鈕3");
JButton btn4 = new JButton("按鈕4");
panel.add(btn1);
panel.add(btn4);
panel.add(btn2);
panel.add(btn3);
frame.add(panel);
JPanel panel2 = new JPanel();
JButton btn5 = new JButton("按鈕5");
JButton btn6 = new JButton("按鈕6");
JButton btn7 = new JButton("按鈕7");
panel2.add(btn5);
panel2.add(btn6);
panel2.add(btn7);
frame.add(panel2);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
執行結果如下:
以上都用到了一些具體的,比如JButton等控制元件。
事件監聽:
事件源:就是awt包或者swing包中的那些圖形介面元件
事件:每一個事件源都有自己特有的對應事件和共性事件。
監聽器:將可以出發某一個事件的動作都已經封裝到了監聽器中。
以上這些,在java中都已經定義好了,直接獲取物件來用就可以了。我們要做的就是,對產生的動作進行處理
Interface MouseListener
void mouseClicked(MouseEvent e)
在元件上單擊(按下並釋放)滑鼠按鈕時呼叫。
void mouseEntered(MouseEvent e)
當滑鼠進入元件時呼叫。
void mouseExited(MouseEvent e)
當滑鼠退出元件時呼叫。
void mousePressed(MouseEvent e)
在元件上按下滑鼠按鈕時呼叫。
void mouseReleased(MouseEvent e)
在元件上釋放滑鼠按鈕時呼叫。
Interface MouseMotionListener,滑鼠動作監聽
void mouseDragged(MouseEvent e)
在元件上按下滑鼠按鈕然後拖動時呼叫。
void mouseMoved(MouseEvent e)
當滑鼠遊標移動到元件上但沒有按鈕被按下時呼叫。
範例程式碼:
package qf.day04.demo04;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Demo03_EventListener {
public static void main(String[] args) {
JFrame frame = new JFrame("事件監聽");//直接設定標題
//對frame進行基本的設定
frame.setSize(400, 500);
frame.setLocation(300, 100);
frame.setLayout(new FlowLayout());
JButton button = new JButton("按鈕");
frame.add(button);
//給元件新增監聽:
button.addMouseListener(new MouseAdapter() {
int count = 0;
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("滑鼠點選。。"+(count++));
}
});
frame.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
System.out.println("表單上的滑鼠被拖拽了。。"+e.getX()+","+e.getY());
}
});
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
//自己實現,需要實現MouseListener介面中的所有的方法,而MouseAdapter類已經實現了該介面中的所有方法,我們可以直接繼承自MouseAdapter,然後只重寫自己需要的方法即可。
//class MyButtonImple implements MouseListener{
//
// @Override
// public void mouseClicked(MouseEvent e) {
// System.out.println("滑鼠被點選餓了。。");
// }
//
// @Override
// public void mouseEntered(MouseEvent e) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public void mouseExited(MouseEvent e) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public void mousePressed(MouseEvent e) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public void mouseReleased(MouseEvent e) {
// // TODO Auto-generated method stub
//
// }
//
//}
執行結果:
每當滑鼠點選一次,count的值就累加1。
好了,通過以上的學習,我們已經大致掌握瞭如果使用java的swing介面,來建立圖解介面程式,我們需要建立出以下的程式介面,並且能夠通過事件監聽,實現繪畫功能。
好了,接下來我們實現專案的第三步程式碼,新建一個java檔案,D3_DrawPic.java,範例程式碼如下:
package demo;
import java.awt.AWTException;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.RenderableImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.bytedeco.javacpp.indexer.IntRawIndexer;
public class D3_DrawPic {
public static void main(String[] args) {
//1.建立視窗
JFrame frame = new JFrame();
frame.setLayout(new FlowLayout());
frame.setSize(520,700);
frame.setTitle("王二狗的畫板");
//2.建立面板:按鈕區面板,繪畫區面板
DrawPanel drawPanel = new DrawPanel();
drawPanel.setLayout(null);
drawPanel.setPreferredSize(new Dimension(520, 660));
drawPanel.setBackground(Color.WHITE);
ButtonPanel buttonPanel = new ButtonPanel(drawPanel,frame);
buttonPanel.setLayout(new FlowLayout());
buttonPanel.setPreferredSize(new Dimension(520,40));
// buttonPanel.setBackground(Color.BLUE);
//3.將面板,新增到視窗上
frame.add(buttonPanel);
frame.add(drawPanel);
//4.視窗新增監聽
frame.addMouseListener(drawPanel);
frame.addMouseMotionListener(drawPanel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
//按鈕區的畫板
class ButtonPanel extends JPanel{
//設定按鈕面板的一堆按鈕
JButton pencil = new JButton("畫筆");
JButton circle = new JButton("圓");
JButton line = new JButton("直線");
JButton eraser = new JButton("橡皮擦");
JButton next = new JButton("下一幀");
JButton retry = new JButton("重畫");
JButton save = new JButton("儲存");
private DrawPanel drawPanel;
private JFrame frame;
int picture = 0;//圖片的編號
public ButtonPanel(DrawPanel drawPanel,JFrame frame){
this.drawPanel = drawPanel;
this.frame = frame;
this.add(pencil);
this.add(circle);
this.add(line);
this.add(eraser);
this.add(next);
this.add(retry);
this.add(save);
//給這些按鈕,新增監聽。。
pencil.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("普通的繪畫。。。");
drawPanel.setType(0);//0表示普通的繪畫。。
}
});
//畫圓按鈕的
circle.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("要畫圓了。。");
drawPanel.setType(1);//1表示畫圓
}
});
//畫直線的按鈕
line.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("按鈕被點選,表示要畫直線了。。");
drawPanel.setType(2);//2表示畫直線
}
});
//橡皮擦
eraser.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("擦除。。。");
drawPanel.setType(3);//3表示擦除
}
});
//重畫
retry.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("重畫這張圖。。"+picture);
//思路:開啓圖片的目錄,讀取對應的圖片數據--->顯示到視窗,繪圖工具,繪畫這張圖片
String imagepath = "C:\\Ruby\\薩日朗\\換色\\"+picture+".jpg";
System.out.println(imagepath);
File file = new File(imagepath);
System.out.println(file.exists());
try {
//讀取圖片到記憶體中-->BufferedImage
BufferedImage image = ImageIO.read(file);//原始圖片的畫素:112*184
//放大圖片物件
Image image2=image.getScaledInstance(400, 600, Image.SCALE_DEFAULT);//使用預設的影象縮放演算法。
//將放大的圖片,繪畫到面板上
Graphics2D g2 = (Graphics2D) drawPanel.getGraphics();
g2.drawImage(image2, 60, 0, null);
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
//下一幀
next.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
picture++;
System.out.println("下一張。。"+picture);
//思路:開啓圖片的目錄,讀取對應的圖片數據--->顯示到視窗,繪圖工具,繪畫這張圖片
String imagepath = "C:\\Ruby\\薩日朗\\換色\\"+picture+".jpg";
System.out.println(imagepath);
File file = new File(imagepath);
System.out.println(file.exists());
if(!file.exists()){
System.out.println("圖片不存在。。"+picture);
return;//結束方法
}
try {
//讀取圖片到記憶體中-->BufferedImage
BufferedImage image = ImageIO.read(file);//原始圖片的畫素:112*184
//放大圖片物件
Image image2=image.getScaledInstance(400, 600, Image.SCALE_DEFAULT);//使用預設的影象縮放演算法。
//將放大的圖片,繪畫到面板上
Graphics2D g2 = (Graphics2D) drawPanel.getGraphics();
g2.drawImage(image2, 60, 0, null);
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
//繪畫後,進行圖片儲存
save.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("儲存圖片。。"+picture);
//捕捉螢幕的某塊區域-->儲存成圖片
//1.圖片要儲存的路徑
String imagePath = "C:\\Ruby\\薩日朗\\繪圖\\"+picture+".jpg";
System.out.println(frame.getX()+","+frame.getY());
//從螢幕繪畫的區域:4個參數:
//前的兩個表示位置,後的兩個表示寬度和高度
Rectangle rectangle = new Rectangle(frame.getX()+10,frame.getY()+82,500,600);
//建立包含從螢幕讀取的畫素的影象。
try {
BufferedImage image = new Robot().createScreenCapture(rectangle);
File file = new File(imagePath);
ImageIO.write(image, "jpg", file);
System.out.println("儲存了。。"+file.getAbsolutePath());
} catch (AWTException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
}
}
//繪畫區面板
class DrawPanel extends JPanel implements MouseListener,MouseMotionListener{
//繪畫的型別:0代表普通的的的繪畫,1表示畫圓,2表示畫直線,3表示擦除
private int type;
private int xd = 5;//偏移量
private int yd = 80;
int x1, y1; //要繪畫的起點
int x2,y2;//要繪畫終點
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
int r = 30;//橢圓的半徑
@Override
public void mouseClicked(MouseEvent e) {
//當滑鼠在繪畫區點選一下,就產生一個圓圈
System.out.println(e.getX()+","+e.getY());
Graphics2D g2 = (Graphics2D) this.getGraphics();
if(type == 1){//畫圓圈
g2.setColor(Color.RED);//設定繪畫工具的顏色
//詞義,橢圓
Ellipse2D circle = new Ellipse2D.Double();
int x = e.getX();
int y = e.getY();
circle.setFrameFromCenter(x-xd, y-yd, x+r-xd, y+r-yd);
g2.fill(circle);
}
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println("滑鼠按鈕的位置。。");
x1 = e.getX();
y1 = e.getY();
// System.out.println(x1+","+y1);
}
@Override
public void mouseReleased(MouseEvent e) {
x2 = e.getX();
y2 = e.getY();
if(type == 2){//繪畫直線
Graphics2D g2= (Graphics2D) this.getGraphics();
g2.setColor(Color.RED);//顏色,紅色
g2.setStroke(new BasicStroke(15.0f));//畫筆的粗細
x1 -= xd;
y1 -= yd;
x2 -= xd;
y2 -= yd;
Ellipse2D circle =new Ellipse2D.Double();
circle.setFrameFromCenter(x1, y1,x1+7.5,y1+7.5);
g2.fill(circle);
g2.drawLine(x1, y1, x2, y2);
circle.setFrameFromCenter(x2, y2,x2+7.5,y2+7.5);
g2.fill(circle);
System.out.println("畫直線。。。");
}
}
@Override
public void mouseDragged(MouseEvent e) {
x2 = e.getX();
y2 = e.getY();
Graphics2D g2 = (Graphics2D) this.getGraphics();//繪圖工具
if(type == 0 || type == 3){
System.out.println("普通的繪畫。。或者擦除");
g2.setStroke(new BasicStroke(10));//設定畫筆
if(type == 3){//擦除
System.out.println("擦除。。。");
g2.setColor(Color.WHITE);
}else{
g2.setColor(Color.RED);//設定畫筆顏色
}
//使用抗鋸齒來進行繪畫
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawLine(x1-xd, y1-yd, x2-xd, y2-yd);
x1 = x2;
y1 = y2;
}
}
@Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
}
執行結果如下:
上面的程式執行起來,就可以進行每一張圖片的繪畫了。
Java實現手繪火柴人
我們需要將C:\Ruby\薩日朗\換色,目錄下的所有圖片,一張一張繪畫,儲存到指定的C:\Ruby\薩日朗\繪圖,這個目錄下。