一、知识点
(一)实现画图程序所需要的APT类:
import java.awt.Color; import java.awt.FlowLayout; import java.awt.Graphics; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.text.AbstractDocument.Content; /** * 定义一个画图界面类,该类继承自JFrame窗体类. */ public class DrawFrame extends JFrame { /** * 程序入口主函数 */ public static void main(String[] args) { // 实例化窗体类的对象,调用初始化界面的方法 DrawFrame dl = new DrawFrame(); dl.initUN(); // dl.setBackground(Color.WHITE);这个是错误的不能改变窗体的颜色。 } public void initUN() { setTitle("简单画图"); setSize(600, 500); setDefaultCloseOperation(3); setLocationRelativeTo(null); setLayout(new FlowLayout()); JButton butLine = new JButton("直线"); this.add(butLine); JButton butSquare = new JButton("矩形"); add(butSquare); JButton butRotundity = new JButton("圆"); add(butRotundity); JButton butS = new JButton("任意多边形"); add(butS); JButton but = new JButton("画笔"); add(but); JButton butt = new JButton("刷子"); add(butt); JButton but1 = new JButton("橡皮擦"); add(but1); JButton but2 = new JButton("喷枪"); add(but2); getContentPane().setBackground(Color.WHITE);//getContenPane为 改变窗口的颜色。 /** * //实例化一个流失布局类的对象,布局类是针对容器的,容器上要填多个组件,那么必须要设置排列对齐方式; * java.awt.FlowLayout fl=new java.awt.FlowLayout(); * jf.setLayout(fl);//设置窗体的布局方式为流式布局 //定义一个ImageIcon类,该类用来读取一个磁盘的图片文文件。 */ setVisible(true); Graphics g = getGraphics();// 获取窗体上画笔画布对象(注意:必须要在窗体可见之后才能获取画笔画布对象,否则获取的是null) // 4.在DrawFrame类中实例化LoginListener事件处理类的对象dn; LoginListener dn = new LoginListener(); addMouseListener(dn);// 5.给事件源窗体对象添加addMouseListener()鼠标监听方法,指定事件处理类对象dl. addMouseMotionListener(dn); butLine.addActionListener(dn);// 要加监听方法才能获取数值。 butSquare.addActionListener(dn);// 要加监听方法才能获取数值。 butRotundity.addActionListener(dn);// 要加监听方法才能获取数值。 butS.addActionListener(dn);// 要加监听方法才能获取数值。 but1.addActionListener(dn); but.addActionListener(dn); butt.addActionListener(dn); but2.addActionListener(dn); dn.SetG(g); // dl.SetJ(butS); // dl.SetJ(butRotundity); // dl.SetJ(butSquare); // dl.SetJ(butLine); } }
import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * 1.新建一个LoginListener事件处理类, * 该类实现MouseListener鼠标事件接口,实现接口中的抽象方法。 * 2.定义四个变量,在按下和释放方法中获取按下和释放的坐标值。 3.定义Graphics画笔画布类的对象,调用绘制图形的方法来画图。 我们的组件是画出来的,那么你要在哪一个组件上画图形,那你的画笔画布对象就从这个组件上获取。 4.实例化DrawListener事件处理类的对象,对象名dl 5.给事件源窗体对象添加addMouseListener()鼠标监听方法,指定事件处理类对象dl. */ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.Random; //F3键可以看到代码 public class LoginListener implements MouseListener, ActionListener, MouseMotionListener { public String s; private int X1, X2, Y1, Y2;// 声明四个整数变量,用来记录按下和释放时的坐标值 public int sx,sy,ex,ey;//存储任意多边形的起始点坐标和结束点的坐标 public int count=0;//记录画的是任意多边形的第几条线 Graphics g;// 声明一个画笔画布类的对象名 // 向DrawFrame借画笔画布类的对象。 // public JButton butLine ; // public JButton butSquare; // public JButton butRotundity;不需要用到方法和属性,所以不用声明对象。 // public JButton butS; private Graphics2D g1;// 声明一个画布类的对象;Graphics2D是Graphics的一个子类。 BasicStroke S = new BasicStroke(10); BasicStroke C = new BasicStroke(1);// 方法一:实例化画笔粗细。设置画笔粗细为1. public void SetG(Graphics gra) { g = gra;// 把gra给g; g1 = (Graphics2D) gra;// 强制转型 g1.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 设置设置画笔抗锯齿,使线条更加平滑。 } // public void SetJ(JButton jb){ // butLine=jb ; 没有用到对象的方法或者属性就不用传。 // butSquare=jb; // butRotundity=jb; // butS=jb; // } /** * 当你在事件源上发生鼠标按下动作时执行的方法。 */ public void mousePressed(MouseEvent e) { // 取得鼠标按下时取得的坐标; X1 = e.getX(); Y1 = e.getY(); } /** * 当你在事件源上发生鼠标释放动作时执行的方法。 */ public void mouseReleased(MouseEvent e) { X2 = e.getX(); Y2 = e.getY(); if (s.equals("直线")) { g.drawLine(X1, Y1, X2, Y2); } if (s.equals("圆")) { g.drawOval(X1, Y1, X2, Y2); } if (s.equals("矩形")) { g.drawRect(X1, Y1, X2, Y2); } if (s.equals("任意多边形") && count==0) {//判断是否画任意多边形的第一条线 g.drawLine(X1, Y1, X2, Y2); //存储第一条线的起始点 sx = X1; sy = Y1; //存储第一条线的结束点 ex = X2; ey = Y2; count++;//表示第一条已经画完了 } } /** * 当你的鼠标进入到事件源是行时执行的方法。 */ public void mouseEntered(MouseEvent e) { } /** * .当你的鼠标离开到事件源是行时执行的方法。 */ public void mouseExited(MouseEvent e) { } /** * 当你在事件源上发生鼠标点击动作时执行的方法。(在同一个位置上按下并释放才会执行点击) */ public void mouseClicked(MouseEvent e) { if (s.equals("任意多边形") && count!=0) {//判断是否已经画完任意多边形的第一条线了 //获取点击的坐标值 int x = e.getX(); int y = e.getY(); if(e.getClickCount()==2){//判断是双击,图形要闭合 //使用x,y和ex,ey画闭合的第一条线 g.drawLine(ex, ey, x, y); //使用x,y和sx,sy画闭合图形的最后 一条线 g.drawLine(sx, sy, x, y); //改变count的值,好让下一次又是重新开始新的多边形 count=0; }else{//判断不是双击,要接下来的线 //根据上一条线的结束点和当前点击的坐标,来绘制直线 g.drawLine(ex, ey, x, y); //将当前这条线的结束赋给ex,ey,作为下一条线的起始点 ex = x; ey = y; } } } public void actionPerformed(ActionEvent e) { // 得到按钮上的文字; s = e.getActionCommand(); // getActionCommand()的方法是ActionEvent的,也就是e的。 } @Override // 当鼠标拖动时,在事件源上按下鼠标按键然后拖动鼠标时执行的方法。 public void mouseDragged(MouseEvent e) { if (s.equals("画笔")) { /** * 因为在拖动过程当中会不断取点,如果起点固定则画出来的都是在一个点开始的。 * 以上一个拖动取到的坐标作为下一段直线的起点,从而画出曲线。 */ X2 = e.getX(); Y2 = e.getY(); g1.drawLine(X1, Y1, X2, Y2); X1 = X2;// 转换坐标。 Y1 = Y2; } if (s.equals("刷子")) { g1.setStroke(S);// 要进行转换画笔,再画;设置线条的粗细。 X2 = e.getX(); Y2 = e.getY(); g1.drawLine(X1, Y1, X2, Y2); X1 = X2; Y1 = Y2; g1.setStroke(C); } if (s.equals("橡皮擦")) { g1.setStroke(S); g1.setColor(Color.WHITE); // 设置线条的颜色为白色来绘制橡皮擦。 X2 = e.getX(); Y2 = e.getY(); g1.drawLine(X1, Y1, X2, Y2); X1 = X2; Y1 = Y2; g1.setColor(Color.black);// 在画完之后转换回一般的格式就可以不用在每个都设置。粗细也是。 g1.setStroke(new BasicStroke(1));// 设置粗细法二。 } if (s.equals("喷枪")) { g1.setStroke(C); X2 = e.getX(); Y2 = e.getY(); Random rand = new Random();// 实例化一个随机数类的对象 int size = rand.nextInt(50) + 20;// 随机决定要画的点数,size的范围在20到69之间。没有“+20”时,只有0到49之间 for (int i = 0; i < size; i++) { int x = rand.nextInt(8);// 在0到7之间随机取点。 int y = rand.nextInt(8); g1.drawLine(X2 + x, Y2 + y, X2 + x, Y2 + y);// 有随机数来改变坐标,在X2,Y2附件画点。 } g1.setColor(Color.black); g1.setStroke(C); } } @Override /* * 当在事件源上移动鼠标时执行的方法。 */ public void mouseMoved(MouseEvent e) { } }
JFrame 窗体容器组件类
JButton 按钮元素组件类
ActionListenner 动作事件接口类
ActionEvent 动作事件对象类
MouseListenner 鼠标事件接口类
MouseEvent 鼠标事件对象
Graphics 画笔画布类
(二)界面实现
DrawFrame extends JFrame
(三)功能的实现
- 在窗体上点击JButton的按钮,来绘制直线,矩形,圆,任意多边形。
- 事件机制:
- 事件源对象:窗体,JButton按钮元素组件
- 事件监听方法:addMouseLIstener(MouseListener l)监听窗体,用 addActionListener(ActionListener l)监听JButton元素组件,获取按钮上面的文字来进行判断当前要画的图形。
- 事件接口(事件处理类):MouseListener ,ActionListener,(定义一个LoginListener事件处理类) 不能直接实例化事件接口,需要定义一个事件处理类来实例化事件接口
- 步骤:
- 定义DrawFrame类继承JFrame类,实例化一个窗体类的对象,调用初始化对象的方法;在初始化界面方法中添加需要的组件。
- 定义一个LoginListener事件处理类,继承MouseListener,ActionListener,实例化这两个接口中的方法;
- 把DrawFrame类中的画布传到LoginListener类中。
- LoginListener中声明画布对象; {private Graphics2D g1;// 声明一个画布类的对象;Graphics2D是Graphics的一个子类。}
- 定义一个获取画布的方法; {public void setG(Graphics gr) { g = gr;}}
- 在DrawFrame中声明画布Graphics画布类,LoginListener类。{ LoginListener dn = new LoginListener();dn.SetG(g);}
- 申明后调用画布的方法:{ dn.SetG(g);}
- 在DrawFrame中给事件源窗体加上MouseListener的监听方法:
{addMouseListener(dn);// 5.给事件源窗体对象添加addMouseListener()鼠标监听方法,指定事件处理类对象dl.} // 并且给JButton元素组件加上Actionlistener的监听方法: { addMouseMotionListener(dn); butLine.addActionListener(dn);// 要加监听方法才能获取数值。 butSquare.addActionListener(dn);// 要加监听方法才能获取数值。 butRotundity.addActionListener(dn);// 要加监听方法才能获取数值。 butS.addActionListener(dn);// 要加监听方法才能获取数值。 but1.addActionListener(dn); }
- 定义String类型的变量存储Actionevent中的getActioncommand方法取得的数据。{ s = e.getActionCommand();} 定义四个变量存储鼠标按下以及释放时取得的数据。
- 开始画图。在 mouseReleased方法中获取鼠标释放上的数据后,用if条件句来判断所需要画的类型:
-
{ if (s.equals("直线"))
{ g.drawLine(X1, Y1, X2, Y2); } } - 主要的利用的画图方法:
{g.drawLine(X1, Y1, X2, Y2); // 画直线: g.drawRect(X1, Y1, X2, Y2);//画矩形: g.drawOval(X1, Y1, X2, Y2);// 画圆: }
(四)重点以及难点,任意多边形。
- 任意多边形:在画出第一条线之后,再一次鼠标的点击,下一条线和上一条线连接(下一条线的起点是上一条的线的终点)。双击鼠标,图形闭合(第一条的起始点和双击得到的坐标连接,上一条的终点坐标和双击得到的坐标连接)。
- 遇到的问题:画出了第一条线,但是下一条线不能连接。或者只能和起点连接。图形不能闭合。
- 解决思路:
- 每次画下一条线的时候,都记入下终点值。第一条线的起始坐标都要记下来。
- 分开画第一条线和后面的线:用if条件来实现。在mouseReleased方法中画下第一条线,画完之后,记入下起始点和终点的值,同时count++;表示第一条线画完。在mouseClicked方法中实现点击一下画下接下来的线。 3.用e.getClickCount()==2来判断是否是双击,当是双击时,第一条的起始点和双击得到的坐标连接,上一条的终点坐标和双击得到的坐标连接,画出两条线,同时改变count的值,好画下一次的图形。当不是双击时,当前得到的坐标和上一条线的结束点来绘制直线。
(五)写程序中出现的问题:
- 刚开始时没有办法得到画布,没有成功获取窗体上画布的对象。(注意:必须要在窗体可见之后才能获取画笔画布对象,否则获取的是null(空))。注意:必须要在窗体可见之后才能获取画笔画布对象,否则获取的是
- 没有正确的理解事件监听机制,错误的以为要到JButton的组件传过来。(只有当需要用到对象的属性或者方法时,才需要把对象传过来)
- JButton没有加上监听机制,导致不能获取数据。无法实现点击一个按钮,画一个图形。(给JButton组件事件源加上了addActionListenner监听方法);
(六)运行结果:
(七)下一步:
实现画笔,刷子,橡皮擦,喷枪。