学习任何知识是用来实践的,针对之前本人学习的一堆知识,本人定了一个小目标,即利用一个小小的项目来巩固这些知识,这个小小小项目就是绘图板。
绘图板实现原理是根据鼠标的操作在组件上绘制图像,同时根据按下不同的按钮切换不同的画笔(如直线,圆,方形等)。
首先说明一下Graphics类,这个类的对象实例为其关联的组件提供绘画功能及有关方法,具体方法会在项目中详细说明。
我们省略掉制作界面这一步,直接开始实现具体功能。
界面:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class Drawer_ver_3 extends JPanel {
//最终版,这是第三版,本人直接让主界面继承JPanel作为绘图的画板,也可以直接创建新的JPanel
public static void main(String[] args) {
new Drawer_ver_3().show_Drawer();
}
public void show_Drawer() {
JFrame jfr = new JFrame();
jfr.setTitle("Painter");
jfr.setSize(1750, 1250);
jfr.setLocationRelativeTo(null);
jfr.getContentPane().setBackground(Color.WHITE);//设置背景颜色,必须先调用getContentPane()否则无法成功设置
jfr.getContentPane().setVisible(true);//设置背景可视化
//常规创建主界面
JPanel jpc = new JPanel();
jpc.setBackground(Color.BLACK);
jpc.setLayout(new FlowLayout());//在放置按钮的JPanel上使用流式布局。
jpc.setPreferredSize(new Dimension(60, 0));
JPanel jpc1 = new JPanel();
jpc1.setBackground(Color.BLACK);
String[] Str = { "直线", "矩形", "圆形", "椭圆", "三角形", "多边形", "画笔", "橡皮擦", "细", "中", "粗", "空心", "实心"};
Color[] Col = { Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY,
Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.YELLOW, Color.WHITE };
Font f = new Font("黑体", Font.PLAIN, 16);
//设置一些常量,但是推荐自定义一个接口,这些用于方便创建编辑按钮。
Draw_Listener draw = new Draw_Listener();
for (int i = 0; i < Col.length; i++) {
JButton jbu = new JButton();
jbu.setPreferredSize(new Dimension(49, 49));
jbu.setBackground(Col[i]);//
jpc.add(jbu);
jbu.addActionListener(draw);//为每个按钮加入监听器。
}
//完成改变颜色按钮的添加。
jfr.add(jpc,BorderLayout.WEST);//框体布局,JPanel默认为框体布局,方向英文指代放置在不同的对应方位。
for (int i = 0; i < Str.length; i++) {
JButton jbu = new JButton(Str[i]);
jbu.setPreferredSize(new Dimension(85, 50));
jbu.setBackground(Color.WHITE);
jbu.setFont(f);//为按钮文本设置字体
jpc1.add(jbu);
jbu.addActionListener(draw);//为每个按钮加入监听器。
}
//完成改变形状按钮的添加。
jfr.add(jpc1,BorderLayout.NORTH);
this.setBackground(Color.WHITE);
jfr.add(this,BorderLayout.CENTER);
jfr.setDefaultCloseOperation(3);
jfr.setVisible(true);
// 组件在窗体的可见之前加入,画笔在窗体的可见之后。
Graphics g = this.getGraphics();
draw.setG(g);
this.addMouseListener(draw);//必须要加入鼠标监听器,否则MouseMotionListener不会生效。
this.addMouseMotionListener(draw);
}
}
监听器:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
public class Draw_Listener implements MouseMotionListener, ActionListener, MouseListener {
private int x1, x2, y1, y2;
private Graphics g;
private Color c = Color.BLACK;
private String str, str1;
private boolean b = false, em = true;
// b用于控制是否为多边形绘制状态,em为是否空心。
private Stroke st = new BasicStroke(1.0f);
// Stroke用于设置绘制的线粗细。
Draw_Listener() {
}
public void setG(Graphics g) {
this.g = g;
}
public void mousePressed(MouseEvent e) {
if (b) {
Graphics2D g2 = (Graphics2D) g;// 强制转型。
g2.setStroke(st);// 设置粗细
x1 = e.getX();
y1 = e.getY();
// 记录鼠标按下的位置的位置。
}
}
public void mouseReleased(MouseEvent e) {
// 在鼠标释放时绘制出相应的图形。
if (str.equals("直线")) {
x2 = e.getX();
y2 = e.getY();
g.drawLine(x1, y1, x2, y2);
// 此方法是在两点之间绘画出直线。
} else if (str.equals("多边形")) {
// 绘制多边形,原理是释放点和上一个点之间绘制直线。
if (b) {
x2 = e.getX();
y2 = e.getY();
g.drawLine(x1, y1, x2, y2);
b = !b;// 使起点x1,y1保持不变。
} else if (e.getClickCount() == 1) {
// 在鼠标点击数为1时(单击),会将当前位置与上一个位置的点连接。
g.drawLine(x2, y2, e.getX(), e.getY());
x2 = e.getX();
y2 = e.getY();
// 更换上一个点。
} else if (e.getClickCount() == 2) {
// 双击时,将鼠标位置点与上一个点及起点相连。
g.drawLine(x2, y2, e.getX(), e.getY());
g.drawLine(x1, y1, e.getX(), e.getY());
b = !b;// 多边形绘制完成,使起点可以改变位置。
}
} else if (str.equals("矩形")) {
x2 = e.getX();
y2 = e.getY();
if (em)
g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
// 绘制一个空心的矩形,参数为起点x1,y1,宽度,高度。
else
g.fillRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
// 填充一个实心矩形,其他同上述。
} else if (str.equals("圆形")) {
x2 = e.getX();
y2 = e.getY();
if (em)
g.drawArc(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(x1 - x2), 0, 360);
// 同矩形,但是为画椭圆,为了达成圆的效果,因此宽高一致, 最后两项为开始的角度和一共需要绘制的角度,原本用于绘制弧线。
else
g.fillOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(x1 - x2));
// 填充一个实心椭圆。
} else if (str.equals("椭圆")) {
x2 = e.getX();
y2 = e.getY();
if (em)
g.drawArc(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2), 0, 360);
// 画椭圆
else
g.fillOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
// 填充椭圆
} else if (str.equals("三角形")) {
x2 = e.getX();
y2 = e.getY();
int x[] = { x1, x2, Math.min(x1, x2) + Math.abs(x1 - x2) / 2, x1 };
int y[] = { y1, y1, y2, y1 };
if (em) {
for (int i = 0; i < 3; i++) {
g.drawLine(x[i], y[i], x[i + 1], y[i + 1]);
// 空心三角形可以视为三条线组成。
}
} else {
g.fillPolygon(x, y, 4);
// 这个方法会依次按照x,y数组一一对应的位置首位前4位依次连线产生的多边形进行填充。
}
}
}
public void mouseDragged(MouseEvent e) {
if (str != null)
if (str.equals("橡皮擦")) {
g.setColor(Color.WHITE);
g.fillOval(e.getX() - 10, e.getY() - 10, 20, 20);
// 在鼠标拖动的时候画与背景颜色一致的圆覆盖图形已达到橡皮擦的效果。
} else if (str.equals("画笔")) {
g.setColor(c);
g.drawLine(x1, y1, e.getX(), e.getY());
// 不停的在鼠标移动的极微小的两点之间画线以达到画笔的效果。(也可以在鼠标位置画圆)
x1 = e.getX();
y1 = e.getY();
// 更新鼠标上一个位置。
}
}
public void mouseMoved(MouseEvent e) {
}
public void actionPerformed(ActionEvent e) {
em = true;
// 根据不同的按钮加一判断来执行不同结果。
b = true;
str1 = e.getActionCommand();// 获取按钮上的字符串
if (str1.equals("")) {
// 文本为空,说明是改变颜色的按钮。
// 获取当前点击的按钮对象
JButton jbu = (JButton) e.getSource();
// 获取按钮上的背景色
c = jbu.getBackground();
g.setColor(c);
} else if (str1.length() > 1) {
// 说明按钮上有多个字符,不是改变粗细的按钮。
if (str1.equals("空心") || (str1.equals("实心"))) {
if (str1.equals("空心"))
em = true;
else if (str1.equals("实心"))
em = false;
} else {
if (str1.equals("橡皮擦") && (str1.equals("画笔")))
b = false;
else
b = true;
str = str1;// 改变当前绘制的图形。
}
} else {
if (str1.equals("细")) {
// 改变粗细。
st = new BasicStroke(1.0f);
} else if (str1.equals("中")) {
st = new BasicStroke(5.0f);
} else if (str1.equals("粗")) {
st = new BasicStroke(10.0f);
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
效果图:
这便制作完成一个简单的绘图板,及界面,但是这还是不够,还存在许多问题,这个项目还是比较考验细节的处理及对各种工具的灵活运用。
预告,会出现的问题及解决方案。