《Java代码成精了——会跳萨日朗的火柴人》实现步骤三:绘画火柴人

在此之前,我们已经实现项目的第二步,处理了每一张图的颜色,我们让小人的颜色是黑色,背景整体调整为白色。本小节要做的就是在这些图片上进行绘画火柴人。因为我们绘画水平有限,我们希望在原图片的轮廓上进行绘画。

 

一、swing组建

我们要想在已有的图片上进行火柴人绘画,首先得有绘画的图形界面。可以使用java中的swing组建来实现。

谈到Java的图形界面程程,指的就是GUI(图形用户界面)。Graphical User Interface,用图形的方式,来显示计算机操作的界面。

Java为GUI提供的对象都在java.awt和javax.swing两个包中。

  • java.awt,Abstract Window ToolKit(抽象窗口工具包),需要调用本地系统方法实现功能。属重量级控件。
  • javax.swing,在awt的基础上,建立的一套图形界面系统,其中提供了更多的组件,而且完全由Java实现。增强了移植性,属轻量级控件。

相对于AWT而言Swing包中提供了更多的丰富的、快捷的、强大的GUI组件,而且这些组件都是java语言编写而成,因此Swing不依赖本地平台,可以真正做到跨平台运行。通常而言我们把AWT称之为重量级组件,Swing称之为轻量级软件,一般而言Swing组件都是在AWT组件名称前加J。


1、JFrame 窗口

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);//通过点击按钮可以直接关闭程序
	}

}

运行结果如下:


2、JPanel 面板

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);
	}

}

运行结果如下:

3、其他控件

以上都用到了一些具体的,比如JButton等控件。

4、事件监听

事件监听:
    事件源:就是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\萨日朗\绘图,这个目录下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值