java简单画图板的实现

1,登陆界面(JFrame,JLabel)

  我们先来做一个仿QQ的登陆界面,并实现当输入正确的账号和密码时,跳出画图板。       首先,我们要知道,java中的所有界面(窗体,面板及其中的各个元素组件)都是画出来的。而java提供了两个现成的组件用来画这些界面:       1,awt组件                   awt组件是基础组件。这些组件的实现调用了操作系统底层的绘图函数。       2,swing组件                 swing组件是awt组件的扩展。       这里我们使用的是swing组件。            swing组件中包含的常用组件类:      1,容器组件类:                       能添加容器组件和元素组件的类就是容器组件类。(顶级容器之间不能相互添加)           JFrame类:                   窗体容器组件类。   顶级容器。          JPanel类:                   这时我们就要简单了解一下图形界面的布局了。(这里我们只介绍两种最常用的布局)          流式布局(FlowLayOut):JFrame默认为流式布局。也就是说,想象你的整个界面是一张白纸,要在上面写字                                                      或者画画,而流式布局规定只有当一行写满时才会跳到下一行。          当我们的界面相对复杂一些的时候,我们就需要边框布局:          边框布局(BorderLayOut):JPanel默认为边框布局。让我们用图形来更清晰的认识一下这种布局:                        如图,这种布局将面板分为五个部分,每一个部分分别都是一个容器组件。
举个例子:

 这段代码就创建了一个北边的面板,这时我们就可以在这个面板上添加所需的按钮了                                                    2,元素组件类:                 JLabel标签元素组件类显示文字或者图片                 JTextField文本输入框元素组件类接收输入信息,将输入信息显示出来
                JPasswordField密码输入框元素组件类接收输入信息,将输入的信息以某个符号代替显示
                JCheckBox复选框(多选框)元素组件类首先又一个选择框,在选择框后还能显示文字或者图片信息
                JButton按钮元素组件类显示文字或图片,提供一个点击效果
以即将开始做的登录界面为例:
     3,辅助类:帮助组件完成某一个功能的类
                javax.swing.ImageIcon图标类将磁盘上的图片文件加载到程序中。
                java.awt.FlowLayout流式布局类流式布局类似word文档(所有的布局类都只能应用于容器组件上)                                                                               在java.awt和javax.swing包下所有以Layout结尾的类都是布局类
               java.awt.Dimension封装类用来封装组件的宽度和高度
//登录界面
package Login_Drawing;
import java.awt.BorderLayout;
import java.awt.Dimension;import javax.swing.*;public class LoginFrame {public void login() {JFrame frame = new JFrame();frame.setSize(550,450);frame.setLocationRelativeTo(null);frame.setDefaultCloseOperation(3);frame.setTitle("天天画图登录");JPanel panel = new JPanel();       //北边的面板(背景图片)frame.add(panel,BorderLayout.NORTH);JPanel panel2 = new JPanel();       //西边的面板(头像图片)frame.add(panel2,BorderLayout.WEST);JPanel panel3 = new JPanel();     //中间的面板frame.add(panel3,BorderLayout.CENTER);ImageIcon image = new ImageIcon(this.getClass().getResource("053.jpg"));    //背景图片JLabel lab = new JLabel(image);lab.setPreferredSize(new Dimension(550,200));panel.add(lab);       ImageIcon image2 = new ImageIcon(this.getClass().getResource("052.jpg"));    //头像图片JLabel lab2 = new JLabel(image2);lab2.setPreferredSize(new Dimension(130,130));panel2.add(lab2);JTextField text = new JTextField(); text.setPreferredSize(new Dimension(300, 30));panel3.add(text);JLabel label = new JLabel("  账号");panel3.add(label);JPasswordField password = new JPasswordField();password.setPreferredSize(new Dimension(300, 30));panel3.add(password);JLabel label2 = new JLabel("  密码");panel3.add(label2);JCheckBox box1 = new JCheckBox("记住密码                        ");panel3.add(box1);JCheckBox box2 = new JCheckBox("自动登录                        ");panel3.add(box2);JButton but = new JButton("安全登录 ");but.setPreferredSize(new Dimension(270, 30));panel3.add(but);LoginLis lis = new LoginLis(frame);but.addActionListener(lis);frame.setVisible(true);lis.setText(text);lis.setPassword(password);}public static void main(String[] args) {// TODO Auto-generated method stubLoginFrame log = new LoginFrame();log.login();}}


运行结果:



   登陆界面做出来了,接下来就是这两件事情了:
             1,实现输入正确的账号和密码,并点击“安全登陆”按钮时,可以弹出画图板界面;              2,弹出画图板的同时,关闭登陆界面    为了实现这两个功能,我们就需要用到事件监听机制。

2,事件监听机制:

     首先,让我们来先了解一下什么是事件源对象,事件监听方法和事件接口(时间处理类):             1,事件源对象:                  首先我们要知道的是,所有的容器组件和元素组件都可以成为事件源对象。而在一个界面上,我们怎么知道哪个组件是事件源对象呢?答案是:你的动作发生在哪个组件上,哪个组件就是事件源对象。举个例子,当我们希望用鼠标在面板frame上拖动时,可以画出线条,那么这时你希望捕捉的动作是鼠标的拖动,这个动作发生在frame面板上。这时,frame面板就是事件源对象。                   而我们现在要做的事是,当鼠标点击按钮时,跳出画图板。我们要捕捉的动作是鼠标点击,这个动作发生在按钮“安全登陆”上,那么,“安全登陆”按钮就是我们的事件源对象。             2,事件监听方法:                  addActionListener(ActionListener l);动作监听方法
用来捕获类似输入框组件上是否有键盘的灰尘动作和类似按钮组件上是否有鼠标的点击动作发生,如果有该监听方法会捕获这个动作,然后
将动作交给参数ActionListener类型的对象进行处理。
            3,事件接口(事件处理类)
ActionListener动作事件接口
actionPerformed(ActionEvent e)是动作事件接口中的事件处理方法。
当ActionListener动作事件接口的对象对事件进行处理时,会调用事件处理方法,执行方法中的代码。
  

3,简单画图板的实现:

       现在,我们就可以实现我们的画图板啦!       首先,我们先来实现画图板最基本,也是最简单的功能:                  画直线,矩形,空心椭圆,实心椭圆,实心正圆(3D效果);                  设置线条颜色和粗细;                  设置抗锯齿。      怎么能实现这些功能呢?先让我们在面板上添加对应的按钮吧。
                 添加按钮时,我们要注意到一个细节:如果我们要添加的按钮很多时,对每一个按钮都单独进行定义和添      加是及其繁琐和不便的。这时,我们就可以使用数组,存储所有的按钮名称,然后在循环遍历数组时一起定义或        添加监 听,(当然,存储颜色按钮的数组是Color类型的),像这样:                 监听类:
//登录监听,画板界面
package Login_Drawing;import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;public class LoginLis implements ActionListener {public JTextField textfield;public JPasswordField passwordfield;public JFrame login; // 传递登录界面public Graphics g;public LoginLis(JFrame login) {this.login = login;}public void setText(JTextField textfield) {this.textfield = textfield;}public void setPassword(JPasswordField password) {this.passwordfield = password;}@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubLoginLis lis = new LoginLis(login);String str1 = textfield.getText();String str2 = passwordfield.getText();if ((str1.equals("123456")) && (str2.equals("0000"))) {lis.drawFrame(lis);} else {JOptionPane.showMessageDialog(login, "账号或密码输入错误!!!");}}public void drawFrame(LoginLis lis) {JFrame frame = new JFrame();frame.setTitle("能不能学习啦的画图板");frame.setDefaultCloseOperation(3);frame.setSize(850, 800);frame.setLocationRelativeTo(null);JPanel panel_01 = new JPanel();// 东边面板panel_01.setPreferredSize(new Dimension(160, 800));panel_01.setBackground(Color.gray);frame.add(panel_01, BorderLayout.EAST);JTextArea area = new JTextArea();area.setPreferredSize(new Dimension(150, 800));area.setBackground(Color.lightGray);panel_01.add(area);DrawLis dl = new DrawLis(area);JPanel panel_02 = new JPanel(); // 北边面板(存放铅笔,喷枪等工具按钮和颜色按钮)panel_02.setPreferredSize(new Dimension(850, 50));panel_02.setBackground(Color.gray);frame.add(panel_02, BorderLayout.NORTH);String[] str_01 = { "一像素", "十像素", "喷枪", "橡皮" ,"图形比较"};Color[] color = { Color.black, Color.BLUE, Color.GREEN, Color.ORANGE };for (int i = 0; i < str_01.length; i++) {JButton button_01 = new JButton(str_01[i]);panel_02.add(button_01);button_01.setPreferredSize(new Dimension(100, 30));button_01.addActionListener(dl);}for (int i = 0; i < color.length; i++) {JButton button_02 = new JButton();button_02.setBackground(color[i]);button_02.setPreferredSize(new Dimension(30, 30));panel_02.add(button_02);button_02.addActionListener(dl);}JPanel panel_03 = new JPanel(); // 西边面板(存放图形按钮)panel_03.setPreferredSize(new Dimension(110, 800));panel_03.setBackground(Color.gray);frame.add(panel_03, BorderLayout.WEST);String[] str_02 = { "直线", "曲线", "空心椭圆", "实心椭圆", "矩形", "实心正圆" };for (int i = 0; i < str_02.length; i++) {JButton button_03 = new JButton(str_02[i]);panel_03.add(button_03);button_03.setPreferredSize(new Dimension(100, 30));button_03.addActionListener(dl);}frame.setVisible(true);frame.addMouseListener(dl);frame.addMouseMotionListener(dl);login.dispose(); // 弹出画图板后关闭登陆界面if (g == null) {g = frame.getGraphics();}System.out.println("界面.g = " + g);dl.setG(g);}}


注意:如果去掉上面的三个set方法,我们就会发现,当点击登陆按钮时,是没办法跳出画图板界面的。这是因为,              

此时在监听类中取得的账号,密码等和登陆界面类中的账号,密码是指向两个不同的空间的。为了取得登陆界    
面中的账号,密码,就必须使用set方法进行传参。

传参过程:(注意是从LoginFrame类传递给LoginLis类)                      LoginLis类:
          
                     LoginFrame类:

   这时,输入正确的账号和密码后点击登录按钮,就会跳出画图板了:  

(画图板太大了,就只截了一部分,嘿嘿嘿。。。)

  4,画图板功能的实现 

      进行到这里,画图板的界面就已经搞定了,这时就可以来实现每个按钮具体的功能啦!       我们先来实现比较简单的(直线,空心椭圆,实心椭圆,矩形,实心正圆的绘制):             由于Graphics类中的画笔画布对象g是可以直接调用该类中的绘制图形方法的,因此这些简单图形的绘制就变得很简单了。(要先取到这个对象,且要注意,Graphics类不可以实例化)             当调用这些绘制图形的方法时,我们可以看到其中所需的参数:             绘制直线:               x1,y1:直线起始点坐标(鼠标按下坐标)             x2,y2:直线终点坐标(鼠标释放坐标)                         绘制矩形:
            这里的参数x1,x2,y1,y2与绘制直线的坐标相同,不同的是,绘制矩形的前两个参数是矩形的左上角坐标,后两个参数是矩形的长和宽。而这里使用Math类中的运算方法是为了使鼠标向各个方向拖动时都可以绘制出图形来。                           绘制空心椭圆:
             前两个参数:椭圆的外切矩形的左上角坐标;              后两个参数:外切矩形的长和宽。                           同理:绘制实心椭圆:
                                            绘制正圆:

              我们可以发现,当绘制这些图形时有一个共性,就是都只需要获取到鼠标按下的坐标和鼠标释放的坐标就可以在这个区间里绘制了。所以,我们只需要使用MouseAdapter类中的MousePressed,MouseReleased方法。               而绘制曲线,喷枪,橡皮擦等图形时,Graphics类中是没有对应的方法可调用的。这时,该怎么办呢? 我们先在电脑自带的画图板上或任意一个画图软件上绘制一条曲线并放大:
    我们看到了什么?一条曲线是由许多条极短的直线收尾相接组成的!     这样,我们就可以仿照这一思路,将曲线绘制出来:
     也就是说,在系统绘制图形的时间片内,先绘制一条直线,并将这条直线的终点坐标赋给下一条即将绘制的直线的起始坐标。      同理,喷枪就是在规定范围内随着鼠标拖动随机生成一定数量的点                 橡皮也是绘制曲线,只是将其颜色设置成背景色。 这样,我们就可以将整个画图板的绘制功能实现出来了!

//画板监听
package Login_Drawing;import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Random;import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;@SuppressWarnings("serial")
public class DrawLis extends JDialog implements ActionListener, MouseListener, MouseMotionListener {public Graphics g;public JTextArea area;public JTextField id1, id2;public JLabel label1, label2;public String str = "直线";public Color color = Color.BLACK;public ArrayList shape;public String type;public double S;public double C;public double length;public int x1, x2, y1, y2;public int id = 0;Random r = new Random();public void setG(Graphics g) {this.g = g;System.out.println("监听.g = " + g);}public DrawLis(JTextArea area) {this.area = area;shape = new ArrayList();}@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubstr = e.getActionCommand();if (str.equals("")) { // 颜色按钮JButton but = new JButton();but = (JButton) e.getSource();color = but.getBackground();System.out.println("Color = " + color);} else {System.out.println("str = " + str);}if (str.equals("图形比较")) {id1 = new JTextField(10);id2 = new JTextField(10);label1 = new JLabel("共有:" + shape.size() + "个图形");label1.setPreferredSize(new Dimension(90, 30));this.add(label1);label2 = new JLabel("          请输入id:                       ");label2.setPreferredSize(new Dimension(170, 30));this.add(label2);this.setLayout(new FlowLayout());this.add(new JLabel("id1 :    "));this.add(id1);this.add(new JLabel(" id2 :    "));this.add(id2);JButton button = new JButton("开始比较");this.add(button);CompareLis cpl = new CompareLis();cpl.setText(id1, id2, shape);button.addActionListener(cpl);this.setBounds(600, 260, 200, 300);this.setDefaultCloseOperation(2);this.setVisible(true);}}public void mousePressed(MouseEvent e) {x1 = e.getX();y1 = e.getY();g.setColor(color);}public void mouseReleased(MouseEvent e) {x2 = e.getX();y2 = e.getY();Shape sh = new Shape(str, S, C, length);shape.add(sh);if (str.equals("一像素")) {((Graphics2D) g).setStroke(new BasicStroke(1));} else if (str.equals("十像素")) {((Graphics2D) g).setStroke(new BasicStroke(10));}else if (str.equals("直线")) {String type1 = "直线";double length1 = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));id++;area.setText("形状:  直线\nid:  " + id + "\n长度:  " + length1);g.drawLine(x1, y1, x2, y2);sh.type = type1;sh.length = length1;}else if (str.equals("空心椭圆")) {String type2 = "空心椭圆";double area2 = 0.25 * Math.PI * Math.abs(x1 - x2) * Math.abs(y1 - y2);double perimeter2 = Math.PI * Math.abs(y1 - y2) + 2 * (Math.abs(x1 - x2) - Math.abs(y1 - y2));id++;area.setText("形状:  空心椭圆\nid:  " + id + "\n面积:  " + area2 + "\n周长:  " + perimeter2);g.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));sh.type = type2;sh.S = area2;sh.C = perimeter2;	} else if (str.equals("实心椭圆")) {String type3 = "实心椭圆";double area3 = 0.25 * Math.PI * Math.abs(x1 - x2) * Math.abs(y1 - y2);double perimeter3 = Math.PI * Math.abs(y1 - y2) + 2 * (Math.abs(x1 - x2) - Math.abs(y1 - y2));id++;area.setText("形状:  实心椭圆\nid:  " + id + "\n面积:  " + area3 + "\n周长:  " + perimeter3);g.fillOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));sh.type = type3;sh.S = area3;sh.C = perimeter3;} else if (str.equals("矩形")) {String type4 = "矩形";double area4 = Math.abs(x1 - x2) * Math.abs(y1 - y2);double perimeter4 = 2 * (Math.abs(x1 - x2) + Math.abs(y1 - y2));id++;area.setText("形状:  矩形\nid:  " + id + "\n面积:  " + area4 + "\n周长:  " + perimeter4);g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));sh.type = type4;sh.S = area4;sh.C = perimeter4;} else if (str.equals("实心正圆")) {int r = Math.abs(x1 - x2);String type5 = "实心正圆";double area5 = Math.PI * r * r;double perimeter5 = 2 * Math.PI * r;id++;area.setText("形状:  正圆\nid:  " + id + "\n面积:  " + area5 + "\n周长:  " + perimeter5);g.fillOval(x2 - r, y2 - r, 2 * r, 2 * r);sh.type = type5;sh.S = area5;sh.C = perimeter5;}}public void mouseDragged(MouseEvent e) {x2 = e.getX();y2 = e.getY();if (str.equals("曲线")) {g.drawLine(x1, y1, x2, y2);x1 = x2;y1 = y2;} else if (str.equals("橡皮")) {((Graphics2D) g).setStroke(new BasicStroke(10));JFrame frame = new JFrame();g.setColor(frame.getBackground());g.drawLine(x1, y1, x2, y2);x1 = x2;y1 = y2;} else if (str.equals("喷枪")) {g.drawLine(x2, y2, x2, y2);for (int i = 0; i < 10; i++) {int p = r.nextInt(10);int q = r.nextInt(10);g.drawLine(x2 + p, y2 + q, x2 + p, y2 + q);}}}@Overridepublic void mouseMoved(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseClicked(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) {// TODO Auto-generated method stub}}
     

5,比较功能的实现

       这里,我们要实现图形的比较功能:        给每个图形赋一个id值,输入希望进行比较的图形的id号进行比较:               当输入的id号不存在时:弹出提示框,报错               当输入的id号对应的两个图形种类不相同时:(实心椭圆,空心椭圆,实心正圆除外)                                                      弹出提示框,输出两个图形的种类并提示无法比较               当输入的id号对应两条直线时:显示比较结果(哪条直线的长度更长)               当输入的id号对应两个其他相同种类图形时:显示比较结果(哪个图形周长更大,哪个图形面积更大) 直线比较:
报错:
                      这一模块中最重要的技术点就在于怎样将绘制出来的图形进行保存:                      只有将所有图形保存起来才能在比较时得到要比较的图形属性。         这里,我先定义了一个Shape类,将图形的属性在其中定义。这样,每次绘制出一个图形时就会实例化一个Shape类的对象。再将这些对象存入Java事先写好的ArrayList<>中,就可以达到我们的目的了。
package Login_Drawing;public class Shape {public String type;public double S;public double C;public double length;public Shape(String type, double S, double C, double length){this.type = type;this.S = S;this.C = C;this.length = length;}}
package Login_Drawing;import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;@SuppressWarnings("serial")
public class CompareLis extends JDialog implements ActionListener {public String str, str1, str2;public JTextField id1;public JTextField id2;public JLabel label1;public JLabel label2;public JLabel input1;public JLabel input2;public DrawLis dl;public ArrayList shape;public void setText(JTextField id1, JTextField id2, ArrayList shape) {this.id1 = id1;this.id2 = id2;this.shape = shape;}public void actionPerformed(ActionEvent e) {str = e.getActionCommand();str1 = id1.getText();str2 = id2.getText();int input1 = Integer.parseInt(str1);int input2 = Integer.parseInt(str2);if (input1 <= 0 || input1 > shape.size() || input2 <= 0 && input2 > shape.size()) {JOptionPane.showMessageDialog(null, "输入越界!!!");}String type1 = shape.get(input1 - 1).type;String type2 = shape.get(input2 - 1).type;double length1 = shape.get(input1 - 1).length;double length2 = shape.get(input2 - 1).length;double area1 = shape.get(input1 - 1).S;double area2 = shape.get(input2 - 1).S;double perimeter1 = shape.get(input1 - 1).C;double perimeter2 = shape.get(input2 - 1).C;if (str.equals("开始比较")) {// 输入的两个id相同时if (str1.equals(str2) == true) {JOptionPane.showMessageDialog(null, "输入错误!!!");}// 输入的id范围错误else if (input1 <= 0 || input1 > shape.size() || input2 <= 0 || input2 > shape.size()) {JOptionPane.showMessageDialog(null, "输入的id越界");}// 对比的两个图形形状不同else if (type1.equals(type2) == false) {// 两个图形一个为实心椭圆,一个为空心椭圆if (type1.equals("空心椭圆") && type2.equals("实心椭圆") || (type1.equals("实心椭圆")) && type2.equals("空心椭圆")) {if (area1 >= area2) {JOptionPane.showMessageDialog(null, "第一个图形面积更大");} else {JOptionPane.showMessageDialog(null, "第二个图形面积更大");}// frame.add(label2);// JLabel label3 = new JLabel();// label3.setPreferredSize(new Dimension(300, 30));if (perimeter1 >= perimeter2) {JOptionPane.showMessageDialog(null, "第一个图形周长更大");} else {JOptionPane.showMessageDialog(null, "第二个图形周长更大");}}// 两个图形形状不同else {JOptionPane.showMessageDialog(null,"id为" + input1 + "的图形是" + type1 + "\nid为" + input2 + "的图形是" + type2 + "\n形状不同,无法比较!");}}// 相同形状的图形的比较else {if (type1.equals("直线") && type2.equals("直线")) {if (length1 >= length2) {JOptionPane.showMessageDialog(null, "第一条直线更长");} else {JOptionPane.showMessageDialog(null, "第二条直线更长");}} else {// JLabel label2 = new JLabel();// label2.setPreferredSize(new Dimension(300, 30));if (area1 >= area2) {JOptionPane.showMessageDialog(null, "第一个图形面积更大");} else {JOptionPane.showMessageDialog(null, "第二个图形面积更大");}// frame.add(label2);// JLabel label3 = new JLabel();// label3.setPreferredSize(new Dimension(300, 30));if (perimeter1 >= perimeter2) {JOptionPane.showMessageDialog(null, "第一个图形周长更大");} else {JOptionPane.showMessageDialog(null, "第二个图形周长更大");}// frame.add(label3);////// frame.setVisible(true);}}}}
}
以上,就是我们已经实现好的画图板了。        还有更多功能可以添加,未来不定期更新,敬请期待。。。。








本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部