综合案例--绘图软件
知识点:
1.多态、抽象类的使用
2.java垃圾回收机制的初步认识
3.特别注意:防止内存泄漏,java虽然有垃圾回收机制,但是不当的编码也会造成内存的泄漏
4.给窗口或者窗口上的控件注册事件监听器有三种方法:
- 1.创建匿名内部类的对象(就地实例化)---创建匿名内部类的对象--内部类可以直接使用外部类的私有成员属性和方法
- 2..创建一个内部类对象充当监听器(相较于匿名内部类有名字,可以随时创建对象)
- 3.让窗口实现接口,让窗口对象(this)充当事件监听器
5.lambda表达式的使用
- 从java8开始,对于单方法接口(函数式接口),可以使用lambda表达式写一个匿名方法来编写事件回调代码
6.工厂类的使用:用工厂创建对象(跟具体的图形类型实现解耦合)
代码:
package com.MyPaintBrush;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
@SuppressWarnings("serial")
class PaintBrushFrame extends JFrame
{
private BufferedImage image = new BufferedImage(800, 600, 1);
private List<Shape> shapesArray =new ArrayList<Shape>();
private String currentType = "线条";
private Color defaultColor = Color.BLACK;
private float currentWidth = 0;
public PaintBrushFrame()
{
this.setTitle("绘图工具");
this.setSize(800, 600);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel buttonPannel = new JPanel();
this.add(buttonPannel, BorderLayout.SOUTH);
String[] buttonNames =
{ "线条", "矩形", "椭圆", "三角形" };
for (String name : buttonNames)
{
JButton button = new JButton(name);
button.addActionListener(evt ->
{
currentType = evt.getActionCommand();
});
buttonPannel.add(button);
}
String[] buttonNames2 =
{ "选择颜色", "-", "+", "撤销", "清空", "保存" };
for (String name : buttonNames2)
{
JButton button = new JButton(name);
button.addActionListener(evt ->
{
String command = evt.getActionCommand();
if (command.compareTo("选择颜色") == 0)
{
// PaintBrushFrame.this此参数相对于窗口居中,null相对于屏幕居中
Color currentColor =
JColorChooser.showDialog(PaintBrushFrame.this, "请选择颜色", defaultColor);
defaultColor = currentColor != null ? currentColor : defaultColor;
} else if (command.equals("-"))
{
if (currentWidth >= 1)
{
currentWidth--;
}
} else if (command.equals("+"))
{
currentWidth++;
} else if (command.equals("撤销"))
{
if (shapesArray.size() > 0)
{
// 特别注意!!!(防止内存泄漏)
shapesArray.remove(shapesArray.size()-1);
repaint();
}
} else if (command.equals("清空"))
{
if (!shapesArray.isEmpty())
{
shapesArray.clear();
/*
* --java虽然有垃圾回收机制(Garbage Collection),但是如果程序
* 编写不当仍然会造成内存泄漏。
* --垃圾回收是针对内存堆空间的无用对象清理工作
*/
repaint();
}
} else if (command.equals("保存"))
{
JFileChooser chooser = new JFileChooser();
int choose = chooser.showSaveDialog(PaintBrushFrame.this);
if (choose == JFileChooser.APPROVE_OPTION)
{
BufferedImage newImage = new BufferedImage(800, 600, 1);
Graphics grp = newImage.getGraphics();
grp.setColor(Color.WHITE);
grp.fillRect(0, 0, 800, 600);
for (int i = 0; i <shapesArray.size(); i++)
{
shapesArray.get(i).draw(grp);
}
try
{
ImageIO.write(newImage, "PNG", chooser.getSelectedFile());
} catch (IOException e1)
{
e1.printStackTrace();
}
}
}
});
buttonPannel.add(button);
}
// 创建匿名内部类的对象--内部类可以直接使用外部类的私有成员属性和方法
// 缺省适配模式
//总结:给窗口或者窗口上的控件注册事件监听器有三种方法:
// 1.创建匿名内部类的对象(就地实例化)
// 2.创建一个内部类对象充当监听器(相较于匿名内部类有名字,可以随时创建对象)
// 3.让窗口实现接口,让窗口对象(this)充当事件监听器
//从java8开始,对于单方法接口(函数式接口),可以使用lambda表达式写一个匿名方法来编写事件回调代码
MouseAdapter msa = new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
{
int x = e.getX();
int y = e.getY();
//用工厂创建对象(跟具体的图形类型实现解耦合)
Shape currentShape = ShapeFactory.createShape(currentType);
currentShape.setColor(defaultColor);
currentShape.setLineWidth(currentWidth);
currentShape.setStartX(x);
currentShape.setStartY(y);
currentShape.setEndX(x);
currentShape.setEndY(y);
shapesArray.add(currentShape);
}
}
@Override
public void mouseDragged(MouseEvent e)
{
{
Shape currentShape = shapesArray.get(shapesArray.size()-1);
int x = e.getX();
int y = e.getY();
currentShape.setEndX(x);
currentShape.setEndY(y);
repaint();
}
}
};
this.addMouseListener(msa);
this.addMouseMotionListener(msa);
}
// 此方法也属于回调方法(call back)
@Override
public void paint(Graphics g)
{
Graphics othreGraphics = image.getGraphics();
super.paint(othreGraphics);
for (int i = 0; i < shapesArray.size(); i++)
{
shapesArray.get(i).draw(othreGraphics);
}
g.drawImage(image, 0, 0, null);
}
public static void main(String[] args)
{
new PaintBrushFrame().setVisible(true);
}
}
package com.MyPaintBrush;
import com.MyPaintBrush.Line;
import com.MyPaintBrush.Oval;
import com.MyPaintBrush.Rect;
import com.MyPaintBrush.Shape;
import com.MyPaintBrush.Triangle;
/**
* 简单(静态)工厂模式
*
* @author YY
*
*/
public class ShapeFactory
{
//静态的方法或对象属于类,不属于这个类的任何一个对象
/**
* 创建图形的工厂方法
* @param shapeType 类型
* @return 图形对象或者nulll
*/
public static Shape createShape(String shapeType)
{
Shape currentShape=null;
switch (shapeType)
{
case "矩形":
currentShape=new Rect();
break;
case "椭圆":
currentShape=new Oval();
break;
case "三角形":
currentShape=new Triangle();
break;
case "线条":
currentShape=new Line();
break;
}
return currentShape;
}
}
package com.MyPaintBrush;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
/**
* 图形(抽象类)
*
* @author YY
*
*/
public abstract class Shape
{
protected int startX; //起点横坐标
protected int startY; //起点纵坐标
protected int endX; //终点横坐标
protected int endY; //终点纵坐标
protected Color color; //颜色
protected float lineWidth; // 画笔的粗细
public void draw(Graphics g)
{
g.setColor(color);
((Graphics2D) g).setStroke(new BasicStroke(lineWidth));//设置画笔粗细
}
public void setStartX(int startX)
{
this.startX = startX;
}
public void setStartY(int startY)
{
this.startY = startY;
}
public void setEndX(int endX)
{
this.endX = endX;
}
public void setEndY(int endY)
{
this.endY = endY;
}
public void setColor(Color color)
{
this.color = color;
}
public void setLineWidth(float lineWidth)
{
this.lineWidth = lineWidth;
}
}
package com.MyPaintBrush;
import java.awt.Graphics;
public class Line extends Shape
{
@Override
public void draw(Graphics g)
{
super.draw(g);
g .drawLine(startX, startY, endX, endY);
}
}
package com.MyPaintBrush;
import java.awt.Graphics;
public class Oval extends Shape
{
public void draw(Graphics g)
{
super.draw(g);
int x=startX<endX?startX:endX;
int y=startY<endY?startY:endY;
int width=Math.abs(startX-endX);
int heigh=Math.abs(startY-endY);
g.drawOval(x,y,width,heigh);
}
}
package com.MyPaintBrush;
import java.awt.Graphics;
public class Rect extends Shape
{
public void draw(Graphics g)
{
super.draw(g);
int x=startX<endX?startX:endX;
int y=startY<endY?startY:endY;
int width=Math.abs(startX-endX);
int heigh=Math.abs(startY-endY);
g.drawRect(x,y,width,heigh);
}
}
package com.MyPaintBrush;
import java.awt.Graphics;
public class Triangle extends Shape
{
public void draw(Graphics g)
{
super.draw(g);
int x1 = startX > endX ? startX : endX;
int y1 = startY > endY ? startY : endY;
int width = Math.abs(startX - endX);
int x2 = x1 - width;
int y2 = y1;
int x3 = (startX < endX ? startX : endX) + width / 2;
int y3 = startY < endY ? startY : endY;
// g.drawLine(x1, y1, x2, y2);
// g.drawLine(x2, y2, x3, y3);
// g.drawLine(x3, y3, x1, y1);
g.drawPolygon(new int[]{x1, x2, x3},new int[]{y1,y2,y3},3);
}
}