1.JFrame窗体界面(JButton、Graphics、Graphics2D、Color)
创建一个Draw类,在主函数中实例化Draw类,并调用Ondraw方法
public class Draw{
public static void main(String[] args) {
//在主函数中,实例化Draw类的对象,调用初始化界面的方法
Draw draw = new Draw();
draw.Ondraw();
}
在Ondraw中方法中对窗体进行设置、添加等操作
public void Ondraw() {
//在初始化界面的方法中,实例化JFrame窗体容器组件类的对象
JFrame frame = new JFrame();
//设置窗体容器组件对象的属性值:标题、大小、显示位置、关闭操作、可见。
frame.setTitle("画板");
frame.setSize(700,700);
frame.setDefaultCloseOperation(3);
frame.setLocationRelativeTo(null);
//实例化FlowLayout流式布局类的对象,设置对齐方式
FlowLayout fl = new FlowLayout(FlowLayout.CENTER);
frame.setLayout(fl);
String[] typeArray = {"直线","矩形","圆","文字","铅笔","刷子","橡皮","喷枪","长方体"};
for(int i=0;i<typeArray.length;i++) {
JButton button = new JButton(typeArray[i]);
button.setPreferredSize(new Dimension(80,30));
frame.add(button);
}
Color[] colorArray = {Color.red,Color.green,Color.blue};
for(int i=0;i<colorArray.length;i++) {
JButton button = new JButton();
button.setBackground(colorArray[i]);
button.setPreferredSize(new Dimension(30,30));
frame.add(button);
}
frame.setVisible(true);//显示窗体
//获取窗体上的画笔对象
Graphics g = frame.getGraphics();
//在实例化DrawListener类的对象时将获取的窗体对象传递过去
DrawListener dl = new DrawListener(frame);
//给窗体添加鼠标事件监听方法,指定事件的处理类的对象dl;
dl.setG(g);//设置方法将画笔g传到DrawListener
}
}
2.事件监听方法(ActionListener、MouseLististener、MouseMotionListener)
创建一个事件监听类DrawListener
public class DrawListener implements MouseListener,MouseMotionListener,ActionListener {
private int x1,x2,y1,y2;//将坐标设置为属性,可以在不同的方法中使用
//定义Graphics画笔类的对象属性名
//Graphics2D为Graphics的子类,设置线条粗细后要使用Graphics2D来画图
private Graphics2D g;//Graphics2D为Graphics的子类,设置线条粗细后要使用Graphics2D
//定义JFrame窗体类对象属性名,最后用来获取窗体的颜色,制作橡皮擦
private JFrame frame;
public DrawListener(JFrame framel) {
this.frame = frame;
}
//定义一个带Graphics参数的构造方法
public void setG(Graphics g) {
this.g = (Graphics2D) g;
this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);// 设置画笔开启抗锯齿
}
//重写接口MouseListener,MouseMotionListener,ActionListener中所有的抽象方法
public void actionPerformed(ActionEvent e) {
System.out.println("点击的按钮是:"+e.getActionCommand());
if(e.getActionCommand().equals("")) {
JButton button = (JButton) e.getSource();//获取事件源对象
color = button.getBackground();//获取背景颜色
}else {
name=e.getActionCommand();//获取按钮信息
}
public void mouseDragged(MouseEvent e){
System.out.println("拖动");
}
public void mouseMoved(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
System.out.println("点击");
}
public void mousePressed(MouseEvent e) {
System.out.println("按下");
}
public void mouseReleased(MouseEvent e) {
System.out.println("释放");
}
public void mouseEntered(MouseEvent e) {
System.out.println("进入");
}
public void mouseExited(MouseEvent e) {
System.out.println("离开");
}
}
在Draw类中对按钮增加监听方法,即ActionListener,点击按钮时进行对应的操作
实例化事件处理类DrawListener要在添加监听方法前进行,因为添加监听方法要指定事件处理类
String[] typeArray = {"直线","矩形","圆","文字","铅笔","刷子","橡皮","喷枪","长方体"};
for(int i=0;i<typeArray.length;i++) {
JButton button = new JButton(typeArray[i]);
button.setPreferredSize(new Dimension(80,30));
frame.add(button);
button.addActionListener(dl);//添加动作监听方法
}
Color[] colorArray = {Color.red,Color.green,Color.blue};
for(int i=0;i<colorArray.length;i++) {
JButton button = new JButton();
button.setBackground(colorArray[i]);
button.setPreferredSize(new Dimension(30,30));
frame.add(button);
button.addActionListener(dl);//添加动作监听方法
}
同时需要对窗体添加鼠标事件监听方法,指定事件处理类的队象
frame.addMouseListener(dl);
frame.addMouseMotionListener(dl);
3.画图形(直线、矩形、圆、文字、铅笔、刷子、橡皮、喷枪、长方体、颜色)
在鼠标按下时获取第一个坐标值x1,y1
在鼠标释放时获取第二个坐标值x2,y2根据两个坐标值来画直线、矩形、圆
public void mousePressed(MouseEvent e) {
System.out.println("按下");
//在按下和释放的事件处理方法中获取按下和释放的坐标值
x1 = e.getX();
y1 = e.getY();
g.setColor(color);//设置画笔颜色
}
public void mouseReleased(MouseEvent e) {
System.out.println("释放");
x2 = e.getX();
y2 = e.getY();
}
获取第二个坐标值后,根据两个坐标值来画直线、矩形、圆,在鼠标释放后就可进行画图
画图前先判断要画什么图形,在调用相应的方法
public void mouseReleased(MouseEvent e) {
System.out.println("释放");
x2 = e.getX();
y2 = e.getY();
//设置画笔的颜色
//g.setColor(Color.green);
//g.setColor(new Color(100, 100, 100));
//根据按下和释放的坐标值,使用Graphics对象进行画图
g.setStroke(new BasicStroke(1));//设置线条的粗细
switch(name) {
case "直线":
g.drawLine(x1, y1, x2, y2);
break;
case "矩形":
g.drawRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
break;
case "圆":
g.drawOval(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
break;
case "文字":
g.drawString("大学生需要考四级", x1, y1);
break;
}
}
铅笔、刷子、橡皮主要是线条粗细的不同,通过setStroke(new BasicStroke(这里为线条的值,例1,5,10等等))。
这里画图程序的橡皮是通过获取JFrame窗体的背景色来画线,覆盖掉原本的图形颜色,从而达到擦去效果。获取JFrame窗体的颜色,在Draw类中实例化DrawListener的时候把窗体传到DrawListener类中,通过color = frame.getContentPane().getBackground()获取颜色。
铅笔、刷子、橡皮都是在鼠标拖动时完成,要实现铅笔、刷子、橡皮就是是现曲线。
画曲线:
g.drawLine(x1, y1, x2, y2);
x2 = e.getX();
y2 = e.getY();
x1 = x2;
y1 = y2;
接下来实现铅笔、刷子、橡皮,在拖动时进行画图,在鼠标拖动方法下写画图方法
public void mouseDragged(MouseEvent e){
System.out.println("拖动");
x2 = e.getX();
y2 = e.getY();
switch(name) {
case "铅笔":
g.setStroke(new BasicStroke(2));//设置线条的粗细
g.drawLine(x1, y1, x2, y2);//画曲线
x1 = x2;
y1 = y2;
break;
case "刷子":
g.setStroke(new BasicStroke(10));//设置线条的粗细
g.drawLine(x1, y1, x2, y2);//画曲线
x1 = x2;
y1 = y2;
break;
case "橡皮":
color = frame.getContentPane().getBackground();
g.setColor(color);//设置颜色为窗体颜色
g.setStroke(new BasicStroke(50));
g.drawLine(x1, y1, x2, y2);//画曲线
x1 = x2;
y1 = y2;
break;
}
}
喷枪是将所画曲线的点离散掉,需要用到随机数。
Random rand = new Random();
for(int i=0;i<10;i++) {
int p = rand.nextInt(10);
int q = rand.nextInt(10);
g.drawLine(x2+p, y2+q, x2+p, y2+q);
}
x2 = e.getX();
y2 = e.getY();
x1 = x2;
y1 = y2;
长方体需要画三个面,并且用不同的颜色进行填充显示出来。第一步,通过两个点的坐标将正面画出来,然后填充;第二步是顶面,利用两个点的坐标值算出顶面的另两个点的坐标,然后填充顶面;第三步算出右侧面的另两个点,然后填充。
g.setColor(new Color(100, 200, 100));
g.fillRect(Math.min(x1,x2),Math.min(y1,y2),Math.abs(x1-x2),Math.abs(y1-y2));
int a,b,c,d;
a=Math.min(x1, x2);
b=Math.max(x1, x2);
c=Math.min(y1, y2);
d=Math.max(y1, y2);
int m=(int)((b-a)*Math.cos(Math.PI/4)*Math.sin(Math.PI/4));
int n=(int)((b-a)*Math.cos(Math.PI/4)*Math.sin(Math.PI/4));
//顶面
g.setColor(Color.green);
g.fillPolygon(new int[] {a, a+m, b+m,b},new int[] {c,c-n,c-n,c},4);
//右侧面
g.setColor(Color.black);
g.fillPolygon(new int[] {b, b, b+m,b+m},new int[] {c,d,d-n,c-n},4);
4.重绘(数组、重写paint()方法)
在窗体上绘制图像,当改变窗体的大小后,画在窗体上的图像会消失。
原因:每当你改变窗体大小后,改变后的大小和原来的大小不一致了,窗体需要根据新的大小重新再画一次。之前画的图形是画在窗体上,重画窗体的时候,图形没有存储,并不会重画一次。
要将图形重画就要把图形存储起来
每一个图形都是由多个数据组成,并且图形不同,数据的个数也不同,定义类实现这个对象
把每一个图形对象使用数组或者队列存储起来
定义类继承JFrame窗体对象,接下来重写paint(Graphics g)方法
画窗体的方法是paint(Graphics g),在此方法中将存储的图形信息取出来再画一次
需要定义一个Paint类,图形和数据个数不同
public class Paint {
private int x1,y1,x2,y2;
private Color color;
private String name;
private int width;//线条粗细
public Paint(int x1, int y1, int x2, int y2, Color color, String name) {
super();
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.color = color;
this.name = name;
}
public Paint(int x1, int y1, int x2, int y2, Color color, String name, int width) {
super();
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.color = color;
this.name = name;
this.width = width;
}
//可以把方法写在这里,在Draw类和DrawLisyener类中调用
public int getX1() {
return x1;
}
public void setX1(int x1) {
this.x1 = x1;
}
public int getY1() {
return y1;
}
public void setY1(int y1) {
this.y1 = y1;
}
public int getX2() {
return x2;
}
public void setX2(int x2) {
this.x2 = x2;
}
public int getY2() {
return y2;
}
public void setY2(int y2) {
this.y2 = y2;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
}
利用数组将图形信息存储起来
在Draw中定义一个数组,通过DrawLisener的实例化把数组传到DrawListener类中,把图形信息存储到数组中
Draw类中:
private Paint[] array = new Paint[1000];//定义存储图形的数组
DrawListener dl = new DrawListener(frame,array);
DrawListener类中:
private Paint[] array;//定义存储图形的数组
private int index = 0;
public DrawListener(JFrame frame,Paint[] array) {
this.frame = frame;
this.array = array;
}
//存储图形信息
Paint paint = new Paint(x1,y1,x2,y2,color,name,2);//根据图形的数据实例化Paint对象
if(index<1000)
array[index++] = paint;//将数组对象存入到数组中
定义类继承JFrame窗体对象,重写paint(Graphics g)方法,将存储的图形再画一次
继承JFrame窗体对象后,不用实例化JFrame,把全部的frame改为this
public class Draw extends JFrame{
public static void main(String[] args) {
//在主函数中,实例化Draw类的对象,调用初始化界面的方法
Draw draw = new Draw();
draw.Ondraw();
}
private Paint[] array = new Paint[1000];//定义存储图形的数组
private int x1, y1, x2, y2;
//重写父类的重绘方法
public void paint (Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);// 设置画笔抗锯齿
//把存储在数组中的图形数据取出来,重新画一次
for (int i=0;i<array.length;i++) {
Paint p = array[i];//获取数组中指定下标位置的图形对象
if(p!=null) {
x1=p.getX1();
x2=p.getX2();
y1=p.getY1();
y2=p.getY2();
g.setColor(p.getColor());
if(p.getName().equals("直线")) {
g.drawLine(x1, y1, x2, y2);
} else if(p.getName().equals("矩形")) {
g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1-x2),Math.abs(y1-y2));
} else if(p.getName().equals("圆")) {
g.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1-x2),Math.abs(y1-y2));
} else if(p.getName().equals("文字")) {
g.drawString("大学生需要考四级", x1, y1);
} else if(p.getName().equals("铅笔")||p.getName().equals("刷子")||p.getName().equals("橡皮")) {
g2d.setStroke(new BasicStroke(p.getWidth()));
g2d.drawLine(x1, y1, x2, y2);
} else if(p.getName().equals("喷枪")) {
g.drawLine(x1,y1,x2,y2);
} else if(p.getName().equals("长方体")) {
int a,b,c,d;
a=Math.min(x1, x2);
b=Math.max(x1, x2);
c=Math.min(y1, y2);
d=Math.max(y1, y2);
int m=(int)((b-a)*Math.cos(Math.PI/4)*Math.sin(Math.PI/4));
int n=(int)((b-a)*Math.cos(Math.PI/4)*Math.sin(Math.PI/4));
g.setColor(new Color(100, 200, 100));
g.fillRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1-x2),Math.abs(y1-y2));
g.setColor(Color.green);
g.fillPolygon(new int[] {a, a+m, b+m,b},new int[] {c,c-n,c-n,c},4);
g.setColor(Color.black);
g.fillPolygon(new int[] {b, b, b+m,b+m},new int[] {c,d,d-n,c-n},4);
}
else
break;
}
}
}
public void Ondraw() {
//在初始化界面的方法中,实例化JFrame窗体容器组件类的对象
//JFrame frame = new JFrame();
//设置窗体容器组件对象的属性值:标题、大小、显示位置、关闭操作、可见。
this.setTitle("画板");
this.setSize(700,700);
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
//实例化FlowLayout流式布局类的对象,设置对齐方式
FlowLayout fl = new FlowLayout(FlowLayout.CENTER);
this.setLayout(fl);
//在实例化DrawListener类的对象时将获取的画笔对象传递过去
DrawListener dl = new DrawListener(this,array);
String[] typeArray = {"直线","矩形","圆","文字","铅笔","刷子","橡皮","喷枪","长方体"};
for(int i=0;i<typeArray.length;i++) {
JButton button = new JButton(typeArray[i]);
button.setPreferredSize(new Dimension(80,30));
this.add(button);
button.addActionListener(dl);//添加动作监听方法
}
Color[] colorArray = {Color.red,Color.green,Color.blue};
for(int i=0;i<colorArray.length;i++) {
JButton button = new JButton();
button.setBackground(colorArray[i]);
button.setPreferredSize(new Dimension(30,30));
this.add(button);
button.addActionListener(dl);//添加动作监听方法
}
this.setVisible(true);
//获取窗体上的画笔对象
Graphics g = this.getGraphics();
//给窗体添加鼠标事件监听方法,指定事件的处理类的对象dl;
dl.setG(g);//设置方法将画笔g传到DrawListener
this.addMouseListener(dl);
this.addMouseMotionListener(dl);
}
}
源码:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.BasicStroke;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Draw extends JFrame{
public static void main(String[] args) {
//在主函数中,实例化Draw类的对象,调用初始化界面的方法
Draw draw = new Draw();
draw.Ondraw();
}
private Paint[] array = new Paint[100000];//定义存储图形的数组
private int x1, y1, x2, y2;
//重写父类的重绘方法
public void paint (Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);// 设置画笔抗锯齿
//把存储在数组中的图形数据取出来,重新画一次
for (int i=0;i<array.length;i++) {
Paint p = array[i];//获取数组中指定下标位置的图形对象
if(p!=null) {
x1=p.getX1();
x2=p.getX2();
y1=p.getY1