画图板的总结
技术总结:
画图板做到现在,自己想了想,画图板实现的思想是先长骨头再生血肉。骨头即框架:窗体,面板,组件。血肉:监听器,队列,各组件功能的实现。
骨头:
1.对于窗体来说,它相当于一个最大的容器,所有的东西都包含在其中。所以首先要对这个容器进行设计,那么就包括窗体的标题,大小,布局管理器,设置可见,点击退出程序关闭。这里需要注意的是布局管理器,最开始用的流式布局管理器,但是后来因为涉及到整个窗体需要分区,所以就必须用边框布局管理器。说到这里就必须要介绍面板了,即五个区域。
2.总共是五个,分别是NORTH、SOUTH、WEST、EAST、CENTER,根据windows中自带的画图板来一一实现每个区域。而每个区域都是以面板为容器,所以我们也要先设计好面板的样式:大小,背景,布局管理器。其中需要注意的是大小,对于大小,只有窗体的大小可以直接jf.setsize( ).而其他的组件都必须要首先创建Dimension对象,然后用setPreferredSize()添加Dimension对象。而布局管理器根据面板上组件不同的性质来设置。其中比较特别的是SOUTH面板,它的布局管理器是设置为NULL,因为它的组件是用setbounds来确定自己的位置。
3.因为每个区域要实现的功能不同,所以需要不同的组件。设置菜单栏。需要的是JmenuBar、Jmenu、JmenuItem 组件。其中需要注意的是,窗体对象添加菜单栏的时候,不是用add.而是用setJmenuBar。
4.左面板区域实现根据用户的需要来改变所画的图形。于是用按钮组件来体现。1在这里涉及了一个小难点:如何设置按钮的图标。解决方案:首先根据图片保存的地址来创建java.net.URL 对象,然后再用java.net.URL来创建javax.swing.ImageIcon对象,最后添加到按钮上。这个过程中需要注意一个按钮有四种状态:静止,进入,点,选择。所以有四种图标。同时需要注意的是这里因为需要添加的图标很多,所以运用到for循环语句。2因为设置了图标,所以就不需要设置大小了。但是需要设置它的边框。 3为了后面监听器的实现,那么就必须在每个按钮上设置动作命令。 4最后要将所有形状按钮放到一个按钮组。
5.中面板上是要实现画画的功能。所以必须要在其上添加一个画布面板。然后在画布面板上取得画布对象。这里就涉及到了几个很重要的知识:如何保存图片。1学习了数据结构中的数组和队列。对于队列,它是以数组为基础的。写一个队列时,先根据它需要的功能来编写它的接口。感觉这里很有意思,就像一个项目经理根据客户的要求来写一个接口,然后安排团队的其他人去完成。 2 重写父类的画画方法。
6.底面板是用来改变画笔的颜色,根据windows自带的画图板,将这个面板分为三个面板。一个是来呈现选中的颜色,一个是来选颜色,一个是来备注。由于这里流式管理器不好安排三个面板的位置,所以就用setbounds来设置位置。这里颜色的选择和显示都是用标签。需要设置它的大小,边框,背景,透明度。
血肉:
1.监听器。顾名思义,它是用来监视事情的发生和发展,并且因此而做出反应。在使用监听器之前需要先把监听器的方法给实现和编写自己需要的方法。因此涉及到子类,父类的知识。同时因为要把主界面的一些参数传递到监听器中,所以需要重载监听器的构造器。而监听器又是如何实现组件的功能的呢?
* 形状组件:根据形状组选中的按钮的动作命令来判断是要画什么类型的形状。
然后就根据每个形状的特点来写程序,并且要把每次画的图形用队列保留下来。
* 颜色标签:颜色就相对来说比较简单,只需要在mousePressed方法中用e.getSource和e.getButton来设置画笔的颜色。
2.队列。一种数据储存结构。它的最主要的特点是长度可变,不惟一。它是需要根据自己的需要来编写方法和属性,Java中并不自带。在画图板中主要是用来保存图形的。
所以实现仿xp画图板总共可分为两大板块。一个是主窗体上各种组件的实现,还有一个是监听器的实现。如下图:
<!--EndFragment-->
所以亲,我们就开始按上面的导图来开始我们的画图板之旅。
1.主窗体:
<!--EndFragment-->
package finalDraw; import java.awt.BorderLayout; import javax.swing.UIManager; /** * *类说明:主界面的实现 * *@author 彭晨明 E-mail:[email protected] * *@version 创建时间:2012-1-27下午11:22:05 * */ public class DrawUI extends javax.swing.JFrame{ /** * */ private static final long serialVersionUID = 1L; public DrawUI(){ super(); // 创建主界面的窗体 this.setTitle("画图板"); // 设置窗体的大小 this.setSize(600, 500); this.setMinimumSize(new java.awt.Dimension(275, 410)); // 设置窗体的布局管理器 java.awt.BorderLayout drawBor = new java.awt.BorderLayout(); this.setLayout(drawBor); // 创建菜单对象 DrawMenu menuBar = new DrawMenu(); this.setJMenuBar(menuBar); //创建左面板对象 LeftPanel leftPanel=new LeftPanel(); this.add(leftPanel,BorderLayout.WEST); //创建中间面板对象 CenterPanel centerPanel=new CenterPanel(); this.add(centerPanel, BorderLayout.CENTER); //创建底面板对象 FootPanel footPanel=new FootPanel(); this.add(footPanel,BorderLayout.SOUTH); // 设置窗体出现时在屏幕的中间位置 this.setLocationRelativeTo(null); // 设置窗体可见 this.setVisible(true); CenterPanel.obtainGraphics(); CenterPanel.drawPanelAddMouselis(); // 设置窗体大小不可调 this.setResizable(true); // 点击关闭时程序退出 this.setDefaultCloseOperation(3); } public static void main(String args[]) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); new DrawUI(); } catch (Exception e) { e.printStackTrace(); } } }
2.菜单栏:
<!--EndFragment-->
package finalDraw; /** * *类说明:实现菜单的创建 * *@author 彭晨明 E-mail:[email protected] * *@version 创建时间:2012-1-27下午11:22:28 * */ public class DrawMenu extends javax.swing.JMenuBar { public DrawMenu() { super(); // 创建菜单 javax.swing.JMenu fileMenu = new javax.swing.JMenu("文件"); javax.swing.JMenu editMenu = new javax.swing.JMenu("编辑"); javax.swing.JMenu lookMenu = new javax.swing.JMenu("查看"); javax.swing.JMenu imageMenu = new javax.swing.JMenu("图像"); javax.swing.JMenu colorMenu = new javax.swing.JMenu("颜色"); javax.swing.JMenu helpMenu = new javax.swing.JMenu("帮助"); javax.swing.JMenu suofangMenu = new javax.swing.JMenu("缩放"); // 创建菜单项目 javax.swing.JMenuItem newItem = new javax.swing.JMenuItem("新建"); javax.swing.JMenuItem saveItem = new javax.swing.JMenuItem("保存"); saveItem.setAction(MenuActions.SAVE_ACTION); javax.swing.JMenuItem openItem = new javax.swing.JMenuItem("打开"); openItem.setAction(MenuActions.OPEN_ACTION); // 将菜单和菜单项目添加到菜单栏中 fileMenu.add(newItem); fileMenu.add(saveItem); fileMenu.add(openItem); lookMenu.add(suofangMenu); this.add(fileMenu); this.add(editMenu); this.add(lookMenu); this.add(imageMenu); this.add(colorMenu); this.add(helpMenu); } }
3.左面板:
<!--EndFragment-->
package finalDraw; import java.awt.Color; import javax.swing.border.BevelBorder; /** * * 类说明:实现左面板的功能 * * @author 彭晨明 E-mail:[email protected] * * @version 创建时间:2012-1-27下午11:22:42 * */ public class LeftPanel extends javax.swing.JPanel { /** * */ private static final long serialVersionUID = 1L; static javax.swing.ButtonGroup shapeGroup; public LeftPanel() { super(); // 设置左面板的大小 java.awt.Dimension di_left = new java.awt.Dimension(60, 420); this.setPreferredSize(di_left); // 设置左面板的颜色 this.setBackground(new Color(244, 244, 244)); // 设置左面板的布局管理器 java.awt.FlowLayout leftFlowLayout = new java.awt.FlowLayout( java.awt.FlowLayout.LEFT); this.setLayout(leftFlowLayout); // 添加形状按钮 // 1.编写动作命令数组 String[] shapeCommand = { "clip", "choose", "eraser", "fill", "color pickede", "enlarge", "pencil", "brush", "airbrush", "character", "line", "curve", "rect", "polygon", "oval", "rounded rect" }; // 2.创建按钮组 shapeGroup = new javax.swing.ButtonGroup(); // 3.用for循环创建按钮 for (int i = 0; i < shapeCommand.length; i++) { // 创建按钮对象 javax.swing.JRadioButton clip = new javax.swing.JRadioButton(); // 设置按钮图标 // 1.获得源图标的网络地址 java.net.URL url = DrawUI.class.getResource("images/draw" + i + ".jpg"); java.net.URL url1 = DrawUI.class.getResource("images/draw" + i + "-1.jpg"); java.net.URL url2 = DrawUI.class.getResource("images/draw" + i + "-2.jpg"); java.net.URL url3 = DrawUI.class.getResource("images/draw" + i + "-3.jpg"); // 2.根据地址创建不同状态下的ImageIcon对象 javax.swing.ImageIcon icon = new javax.swing.ImageIcon(url); javax.swing.ImageIcon icon1 = new javax.swing.ImageIcon(url1); javax.swing.ImageIcon icon2 = new javax.swing.ImageIcon(url2); javax.swing.ImageIcon icon3 = new javax.swing.ImageIcon(url3); // 3.用不同的ImageIcon来设置按钮的图标 clip.setIcon(icon); clip.setRolloverIcon(icon1); clip.setPressedIcon(icon2); clip.setSelectedIcon(icon3); // 设置按钮的边框 clip.setBorder(null); // 设置按钮的动作命令 clip.setActionCommand(shapeCommand[i]); // 2.1.12使得曲线被默认选中 if (i == 6) { clip.setSelected(true); } shapeGroup.add(clip); this.add(clip); } // 创建显示形状选定的面板 javax.swing.JPanel shapePanel = new javax.swing.JPanel(); // 设置面板的大小 java.awt.Dimension di_shape = new java.awt.Dimension(50, 70); shapePanel.setPreferredSize(di_shape); // 设置面板的颜色 shapePanel.setBackground(new Color(244, 244, 244)); // 设置面板的边框 shapePanel.setBorder(new BevelBorder(1)); // 设置面板的布局管理器 java.awt.FlowLayout shapeFlow = new java.awt.FlowLayout(); shapePanel.setLayout(shapeFlow); this.add(shapePanel); } static public javax.swing.ButtonGroup getButtonGroup(){ return shapeGroup; } }
4.中面板:
<!--EndFragment-->
package finalDraw; import java.awt.Color; import java.awt.Graphics; /** * 中间面板的实现 * * @author 专属于我 * */ public class CenterPanel extends javax.swing.JPanel { /** * */ private static final long serialVersionUID = 1L; public static Graphics g; public static MyPanel drawPanel; private static int[][] pointArray; private static Color[][] pointArray1; public CenterPanel() { super(); // 设置中间面板的大小 java.awt.Dimension di = new java.awt.Dimension(530, 420); // 设置中间窗体的颜色 this.setBackground(new Color(128, 128, 128)); // 设置布局管理器 this.setLayout(null); // 创建画板对象 drawPanel = new MyPanel(); drawPanel.setBounds(5, 5, 300, 300); // 设置画板的颜色 drawPanel.setOpaque(true); drawPanel.setBackground(java.awt.Color.WHITE); // 创建八个标签 javax.swing.JLabel label1 = new javax.swing.JLabel(); javax.swing.JLabel label2 = new javax.swing.JLabel(); javax.swing.JLabel label3 = new javax.swing.JLabel(); javax.swing.JLabel label4 = new javax.swing.JLabel(); javax.swing.JLabel label5 = new javax.swing.JLabel(); javax.swing.JLabel label6 = new javax.swing.JLabel(); javax.swing.JLabel label7 = new javax.swing.JLabel(); javax.swing.JLabel label8 = new javax.swing.JLabel(); label1.setBounds(1, 1, 4, 4); label1.setOpaque(true); label1.setBackground(new Color(197, 231, 246)); label2.setBounds(1, drawPanel.getHeight() / 2, 4, 4); label2.setOpaque(true); label2.setBackground(new Color(197, 231, 246)); label3.setBounds(1, drawPanel.getHeight() + 5, 4, 4); label3.setOpaque(true); label3.setBackground(new Color(197, 231, 246)); label4.setBounds(drawPanel.getWidth() / 2, 1, 4, 4); label4.setOpaque(true); label4.setBackground(new Color(197, 231, 246)); label5.setBounds(drawPanel.getWidth() / 2, drawPanel.getHeight() + 5, 4, 4); label5.setOpaque(true); label5.setBackground(new Color(197, 231, 246)); label6.setBounds(drawPanel.getWidth() + 5, 1, 4, 4); label6.setOpaque(true); label6.setBackground(new Color(197, 231, 246)); label7.setBounds(drawPanel.getWidth() + 5, drawPanel.getHeight() / 2, 4, 4); label7.setOpaque(true); label7.setBackground(new Color(197, 231, 246)); label8.setBounds(drawPanel.getWidth() + 5, drawPanel.getHeight() + 5, 4, 4); label8.setOpaque(true); label8.setBackground(new Color(197, 231, 246)); this.add(label1); this.add(label2); this.add(label3); this.add(label4); this.add(label5); this.add(label6); this.add(label7); this.add(label8); // 设置中间面板的布局管理器 this.add(drawPanel); this.updateUI(); } // 得到画板的画布 public static Graphics obtainGraphics() { g = drawPanel.getGraphics(); return g; } // 以数组的形式保存画布上的点 public static void setPointArray(int[][] pointArray) { CenterPanel.pointArray = pointArray; } public static void setPointArray1(Color[][] pointArray1) { CenterPanel.pointArray1 = pointArray1; } public static int[][] getPointArray() { return pointArray; } public static Color[][] getPointArray1() { return pointArray1; } public static void drawPanelAddMouselis() { drawPanel.addMouseListener(new DrawPanelListener(drawPanel)); } } /** * * 类说明:可以实现重绘的面板 * * @author 彭晨明 E-mail:[email protected] * * @version 创建时间:2012-2-8下午3:17:37 * */ class MyPanel extends javax.swing.JPanel { /** * */ private static final long serialVersionUID = 1L; public void paint(Graphics g) { // 得到图形的数据数组 int[][] pointArray = CenterPanel.getPointArray(); super.paint(g); // 得到整个图像的背景色 int m = this.getBackground().getRGB(); // 判断数组是否为空,如果为空,那么就不执行下面的语句 if (pointArray != null) { for (int i = 0; i < pointArray.length; i++) { for (int j = 0; j < pointArray[i].length; j++) { // 判断该点的颜色是否和整个图像的背景色相同,不同的话就重绘 if (m != pointArray[i][j]) { g.setColor(new Color(pointArray[i][j])); g.drawLine(j, i, j, i); } } } } } }
5.底面板:
<!--EndFragment-->
package finalDraw; import java.awt.Color; import java.awt.event.ComponentEvent; import javax.swing.border.BevelBorder; /** * * 类说明:实现底面板 * * @author 彭晨明 E-mail:[email protected] * * @version 创建时间:2012-1-27下午11:21:23 * */ public class FootPanel extends javax.swing.JPanel { private static javax.swing.JLabel leftLabel; private static javax.swing.JLabel rightLabel; public FootPanel() { java.awt.Dimension di=new java.awt.Dimension(490, 80); this.setPreferredSize(di); this.setMinimumSize(new java.awt.Dimension(260, 80)); this.setOpaque(true); this.setBackground(new Color(244, 244, 244)); this.setLayout(null); javax.swing.JPanel showColorPanel = new javax.swing.JPanel(); showColorPanel.setBounds(0, 5, 31, 31); showColorPanel.setBorder(new BevelBorder(BevelBorder.LOWERED)); showColorPanel.setOpaque(true); showColorPanel.setBackground(java.awt.Color.WHITE); showColorPanel.setLayout(null); leftLabel = new javax.swing.JLabel(); rightLabel = new javax.swing.JLabel(); leftLabel.setBounds(5, 5, 16, 16); rightLabel.setBounds(10, 10, 16, 16); leftLabel.setBorder(new BevelBorder(1, java.awt.Color.WHITE, java.awt.Color.BLACK)); rightLabel.setBorder(new BevelBorder(1, java.awt.Color.WHITE, java.awt.Color.BLACK)); leftLabel.setOpaque(true); rightLabel.setOpaque(true); leftLabel.setBackground(java.awt.Color.BLACK); rightLabel.setBackground(java.awt.Color.WHITE); showColorPanel.add(leftLabel); showColorPanel.add(rightLabel); this.add(showColorPanel); javax.swing.JPanel selectColorPanel = new javax.swing.JPanel(); selectColorPanel.setBounds(31, 5, 224, 32); selectColorPanel.setBorder(null); selectColorPanel.setBackground(java.awt.Color.WHITE); java.awt.FlowLayout colorFlow = new java.awt.FlowLayout(0, 0, 0); selectColorPanel.setLayout(colorFlow); Color color3 = new java.awt.Color(128, 0, 0); Color color4 = new java.awt.Color(128, 128, 0); Color color5 = new java.awt.Color(0, 128, 0); Color color6 = new java.awt.Color(0, 128, 128); Color color7 = new java.awt.Color(0, 0, 160); Color color8 = new java.awt.Color(128, 0, 128); Color color9 = new java.awt.Color(128, 128, 64); Color color10 = new java.awt.Color(0, 64, 64); Color color11 = new java.awt.Color(0, 128, 255); Color color12 = new java.awt.Color(0, 64, 128); Color color13 = new java.awt.Color(128, 0, 128); Color color14 = new java.awt.Color(128, 64, 0); Color color19 = new java.awt.Color(255, 255, 128); Color color20 = new java.awt.Color(128, 255, 128); Color color21 = new java.awt.Color(128, 255, 255); Color color22 = new java.awt.Color(128, 128, 255); Color color23 = new java.awt.Color(255, 0, 128); Color color24 = new java.awt.Color(255, 128, 64); Color[] color = { java.awt.Color.BLACK, java.awt.Color.GRAY, color3, color4, color5, color6, color7, color8, color9, color10, color11, color12, color13, color14, java.awt.Color.WHITE, java.awt.Color.LIGHT_GRAY, java.awt.Color.RED, java.awt.Color.YELLOW, java.awt.Color.GREEN, java.awt.Color.CYAN, java.awt.Color.BLUE, java.awt.Color.MAGENTA, color19, color20, color21, color22, color23, color24 }; javax.swing.JLabel[] colorJLabel = new javax.swing.JLabel[color.length]; java.awt.Dimension di1=new java.awt.Dimension(16,16); for (int i = 0; i < color.length; i++) { javax.swing.JLabel black = new javax.swing.JLabel(); black.setPreferredSize(di1); black.setBorder(new BevelBorder(1, java.awt.Color.WHITE, java.awt.Color.BLACK)); black.setOpaque(true); black.setBackground(color[i]); colorJLabel[i] = black; selectColorPanel.add(black); } FootPanelColorListener lis=new FootPanelColorListener(leftLabel,rightLabel); for(int i=0;i<colorJLabel.length;i++){ colorJLabel[i].addMouseListener(lis); } this.add(selectColorPanel); final javax.swing.JPanel helpPanel = new javax.swing.JPanel(); helpPanel.setBorder(new BevelBorder(0)); helpPanel.setOpaque(true); helpPanel.setBackground(new Color(244, 244, 244)); java.awt.FlowLayout helpFlow = new java.awt.FlowLayout(0, 0, 5); helpPanel.setLayout(helpFlow); javax.swing.JLabel helpLabel = new javax.swing.JLabel( "要获得帮助, 请在“帮助”菜单中,单击“帮助主题”."); helpPanel.add(helpLabel); this.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(ComponentEvent e) { java.awt.Dimension di = new java.awt.Dimension(e.getComponent() .getSize()); helpPanel.setBounds(0, 41, di.width,40); } }); this.add(helpPanel); } static public javax.swing.JLabel getLeftLabel(){ return leftLabel; } static public javax.swing.JLabel getRightLabel(){ return rightLabel; } }
6.监听器:
1.菜单动作监听器:
<!--EndFragment-->
package finalDraw; import java.awt.event.ActionEvent; import pcm.BMPWrite; /** * * 类说明: * * @author 彭晨明 E-mail:[email protected] * * @version 创建时间:2012-2-2下午3:31:21 * */ public class MenuActions { public static final SaveFile SAVE_ACTION = new SaveFile(); public static final OpenFile OPEN_ACTION = new OpenFile(); static public class SaveFile extends javax.swing.AbstractAction { /** * */ private static final long serialVersionUID = 1L; public SaveFile() { this.putValue(NAME, "保存"); } public void actionPerformed(ActionEvent e) { if(!(CenterPanel.getPointArray1()==null)){ if(CenterPanel.getPointArray1().length!=0){ new BMPWrite(CenterPanel.getPointArray1()); } } } } static public class OpenFile extends javax.swing.AbstractAction { /** * */ private static final long serialVersionUID = 1L; public OpenFile() { this.putValue(NAME, "打开"); } public void actionPerformed(ActionEvent e) { try { java.io.FileInputStream fileIn = new java.io.FileInputStream( "C:\\Documents and Settings\\专属于我\\桌面\\java.txt"); java.io.DataInputStream dataIn = new java.io.DataInputStream( fileIn); int[][] pointArray = new int[dataIn.readInt()][dataIn.readInt()]; for (int i = 0; i < pointArray.length; i++) { for (int j = 0; j < pointArray[i].length; j++) { pointArray[i][j] = dataIn.readInt(); } } fileIn.close(); CenterPanel.setPointArray(pointArray); javax.swing.SwingUtilities .updateComponentTreeUI(CenterPanel.drawPanel); } catch (Exception e1) { e1.printStackTrace(); } } } }
Bmp文件读取类:
package pcm; import java.awt.Color; import java.awt.Graphics; import java.io.IOException; /** * * 类说明: * * @author 彭晨明 E-mail:[email protected] * * @version 创建时间:2012-2-3下午8:48:27 * */ public class BMPRead extends javax.swing.JFrame { /** * */ private static final long serialVersionUID = 1L; /** * 位图的宽 */ private static int width; /** * 位图的高 */ private static int height; /** * 位图数据数组,即一个像素的三个分量的数据数组 */ private static int[][] red, green, blue; Graphics g; public static void main(String args[]) { BMPRead bmp = new BMPRead(); bmp.init(); } public void init() { try { // 通过bmp文件地址创建文件输入流对象 java.io.FileInputStream fin = new java.io.FileInputStream( "C:\\Documents and Settings\\专属于我\\桌面\\未命名1.bmp"); // 根据文件输入流对象创建原始数据输入对象 // 这里既可以用原始数据输入流来读取数据,也可以用缓冲输入流来读取,后者速度相比较快点。 // java.io.DataInputStream bis = new java.io.DataInputStream(fin); java.io.BufferedInputStream bis = new java.io.BufferedInputStream( fin); // 建立两个字节数组来得到文件头和信息头的数据 byte[] array1 = new byte[14]; bis.read(array1, 0, 14); byte[] array2 = new byte[40]; bis.read(array2, 0, 40); // 翻译bmp文件的数据,即将字节数据转化为int数据 // 通过翻译得到位图数据的宽和高 width = ChangeInt(array2, 7); height = ChangeInt(array2, 11); // 调用可以将整个位图数据读取成byte数组的方法 getInf(bis); fin.close(); bis.close(); // 创建BMP对象来显示图画 showUI(); } catch (Exception e) { e.printStackTrace(); } } /** * 实现可将四个字节翻译int数据的方法 * * @param array2 * 存储字节的字节数组 * @param start * 起始字节 * @return 返回翻译后的int数据 */ public int ChangeInt(byte[] array2, int start) { // 因为char,byte,short这些数据类型经过运算符后会自动转为成int数据类, // 所以array2[start]&0xff的实际意思就是通过&0xff将字符数据转化为正int数据,然后在进行位运算。 // 这里需要注意的是<<的优先级别比&高,所以必须加上括号。 int i = (int) ((array2[start] & 0xff) << 24) | ((array2[start - 1] & 0xff) << 16) | ((array2[start - 2] & 0xff) << 8) | (array2[start - 3] & 0xff); return i; } /** * 得到位图数据的int数组 * * @param dis * 数据输入流对象 */ public void getInf(java.io.BufferedInputStream bis) { // 给数组开辟空间 red = new int[height][width]; green = new int[height][width]; blue = new int[height][width]; // 通过计算得到每行计算机需要填充的字符数。 // 为什么要填充?这是因为windows系统在扫描数据的时候,每行都是按照4个字节的倍数来读取的。 // 因为图片是由每个像素点组成。而每个像素点都是由3个颜色分量来构成的,而每个分量占据1个字节。 // 因此在内存存储中实际图片数据每行的长度是width*3。 int skip_width = 0; int m = width * 3 % 4; if (m != 0) { skip_width = 4 - m; } // 通过遍历给数组填值 // 这里需要注意,因为根据bmp的保存格式。 // 位图数据中height的值如果是正数的话: // 那么数据就是按从下到上,从左到右的顺序来保存。这个称之为倒向位图。 // 反之就是按从上到下,从左到右的顺序来保存。这个则称之为正向位图。 for (int i = height - 1; i >= 0; i--) { for (int j = 0; j < width; j++) { try { // 这里遍历的时候,一定要注意本来像素是有RGB来表示, // 但是在存储的时候由于windows是小段存储,所以在内存中是BGR顺序。 blue[i][j] = bis.read(); green[i][j] = bis.read(); red[i][j] = bis.read(); // 这里一定要知道,其实系统在给位图数据中添加填充0的时候,都是加在每行的最后。 // 但是我们在使用dis.skipBytes()这个方法的时候,却不一定要在最后一列。 // 系统在填充数据的时候,在数据上加了标记。 // 所以dis.skipBytes()这个方法只要调用了,那么系统就会自动不读取填充数据。 if (j == 0) { bis.skip(skip_width); } } catch (IOException e) { e.printStackTrace(); } } } } public void showUI() { // 对窗体的属性进行设置 this.setTitle("BMP解析");//设置标题 this.setSize(width, height);//设置窗体大小 this.setDefaultCloseOperation(3);//点击关闭,程序自动退出。 this.setResizable(false);//设置窗体大小不可以调节 this.setLocationRelativeTo(null);//设置窗体出现在屏幕中间 //创建自己的panel,用其来显示图形。 //因为如果将图片设置到窗体上显示时,因为jframe是一个复合组件,上面的组件有多个paint方法,所以在paint的时候会画两次, //而panel是只需画一次。 MyPanel panel = new MyPanel(); java.awt.Dimension di = new java.awt.Dimension(width, height);//设置panel大小 panel.setPreferredSize(di); this.add(panel);//窗体添加panel this.setVisible(true);//使窗体可见。 } public class MyPanel extends javax.swing.JPanel { /** * */ private static final long serialVersionUID = 1L; /** * 重写paint方法 */ public void paint(Graphics g) { // 这句话可写可不写,因为这句话是用来画jframe的contentPane的。 // 而这里我们已经在下面定义了contentPane的方法了 super.paint(g); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { g.setColor(new Color(red[i][j], green[i][j], blue[i][j])); // 如果这里画点的话,是不能使用下面注释掉的方法的,不行的话,亲,自己试试吧 // 因为系统在画椭圆的时候,是先画出椭圆的外切矩形。而矩形的边框刚好是占据一个像素点。 // 因此也就出现了,jdk api中说g.drawOval的像素点是width+1,height+1。 // 如果亲,你有更好的理解,请告诉我们。欢迎交流!!! // g.fillOval(j, i, 1, 1); g.fillRect(j, i, 1, 1);// 这里可以使用画点的任何方法,除了上面那种特例。 } } } } }
Bmp文件保存类:
package pcm; import java.awt.Color; /** * * 类说明:实现BMP文件格式的保存 * * @author 彭晨明 E-mail:[email protected] * * @version 创建时间:2012-2-5下午9:06:28 * */ public class BMPWrite { /** * 图形数据数组 */ private Color[][] pointArray; /** * 图形的宽 */ int width; /** * 图形的高 */ int height; /** * BMPWrite构造器的重载,传入图形数据数组 * * @param pointArray */ public BMPWrite(Color[][] pointArray) { this.pointArray = pointArray; this.width = pointArray.length; this.height = pointArray[0].length; this.write(); } /** * 将数据传入内存 */ public void write() { try { // 创建输出流文件对象 java.io.FileOutputStream fos = new java.io.FileOutputStream( "C:\\Documents and Settings\\专属于我\\桌面\\未命名1.bmp"); // 创建原始数据输出流对象 java.io.DataOutputStream dos = new java.io.DataOutputStream(fos); // 给文件头的变量赋值 int bfType = 0x424d; // 位图文件类型(0—1字节) int bfSize = 54 + width * height * 3;// bmp文件的大小(2—5字节) int bfReserved1 = 0;// 位图文件保留字,必须为0(6-7字节) int bfReserved2 = 0;// 位图文件保留字,必须为0(8-9字节) int bfOffBits = 54;// 文件头开始到位图实际数据之间的字节的偏移量(10-13字节) // 输入数据的时候要注意输入的数据在内存中要占几个字节, // 然后再选择相应的写入方法,而不是它自己本身的数据类型 // 输入文件头数据 dos.writeShort(bfType); // 输入位图文件类型'BM' dos.write(changeByte(bfSize),0,4); // 输入位图文件大小 dos.write(changeByte(bfReserved1),0,2);// 输入位图文件保留字 dos.write(changeByte(bfReserved2),0,2);// 输入位图文件保留字 dos.write(changeByte(bfOffBits),0,4);// 输入位图文件偏移量 // 给信息头的变量赋值 int biSize = 40;// 信息头所需的字节数(14-17字节) int biWidth = width;// 位图的宽(18-21字节) int biHeight = height;// 位图的高(22-25字节) int biPlanes = 1; // 目标设备的级别,必须是1(26-27字节) int biBitcount = 24;// 每个像素所需的位数(28-29字节),必须是1位(双色)、4位(16色)、8位(256色)或者24位(真彩色)之一。 int biCompression = 0;// 位图压缩类型,必须是0(不压缩)(30-33字节)、1(BI_RLEB压缩类型)或2(BI_RLE4压缩类型)之一。 int biSizeImage = width * height;// 实际位图图像的大小,即整个实际绘制的图像大小(34-37字节) int biXPelsPerMeter = 0;// 位图水平分辨率,每米像素数(38-41字节)这个数是系统默认值 int biYPelsPerMeter = 0;// 位图垂直分辨率,每米像素数(42-45字节)这个数是系统默认值 int biClrUsed = 0;// 位图实际使用的颜色表中的颜色数(46-49字节),如果为0的话,说明全部使用了 int biClrImportant = 0;// 位图显示过程中重要的颜色数(50-53字节),如果为0的话,说明全部重要 // 因为java是大端存储,那么也就是说同样会大端输出。 // 但计算机是按小端读取,如果我们不改变多字节数据的顺序的话,那么机器就不能正常读取。 // 所以首先调用方法将int数据转变为多个byte数据,并且按小端存储的顺序。 // 输入信息头数据 dos.write(changeByte(biSize),0,4);// 输入信息头数据的总字节数 dos.write(changeByte(biWidth),0,4);// 输入位图的宽 dos.write(changeByte(biHeight),0,4);// 输入位图的高 dos.write(changeByte(biPlanes),0,2);// 输入位图的目标设备级别 dos.write(changeByte(biBitcount),0,2);// 输入每个像素占据的字节数 dos.write(changeByte(biCompression),0,4);// 输入位图的压缩类型 dos.write(changeByte(biSizeImage),0,4);// 输入位图的实际大小 dos.write(changeByte(biXPelsPerMeter),0,4);// 输入位图的水平分辨率 dos.write(changeByte(biYPelsPerMeter),0,4);// 输入位图的垂直分辨率 dos.write(changeByte(biClrUsed),0,4);// 输入位图使用的总颜色数 dos.write(changeByte(biClrImportant),0,4);// 输入位图使用过程中重要的颜色数 // 因为是24位图,所以没有颜色表 // 通过遍历输入位图数据 // 这里遍历的时候注意,在计算机内存中位图数据是从左到右,从下到上来保存的, // 也就是说实际图像的第一行的点在内存是最后一行 for (int i = height - 1; i >= 0; i--) { for (int j = 0; j < width; j++) { // 这里还需要注意的是,每个像素是有三个RGB颜色分量组成的, // 而数据在windows操作系统下是小端存储,对多字节数据有用。 int red = pointArray[i][j].getRed();// 得到位图点的红色分量 int green = pointArray[i][j].getGreen();// 得到位图点的绿色分量 int blue = pointArray[i][j].getBlue();// 得到位图点的蓝色分量 byte[] red1 = changeByte(red); byte[] green1 = changeByte(green); byte[] blue1 = changeByte(blue); dos.write(blue1,0,1); dos.write(green1,0,1); dos.write(red1,0,1); } } //关闭数据的传输 dos.flush(); dos.close(); fos.close(); System.out.println("success!!!"); } catch (Exception e) { e.printStackTrace(); } } /** * 将一个int数据转为按小端顺序排列的字节数组 * @param data int数据 * @return 按小端顺序排列的字节数组 */ public byte[] changeByte(int data){ byte b4 = (byte)((data)>>24); byte b3 = (byte)(((data)<<8)>>24); byte b2= (byte)(((data)<<16)>>24); byte b1 = (byte)(((data)<<24)>>24); byte[] bytes = {b1,b2,b3,b4}; return bytes; } }
2.画图面板监听器:
package finalDraw; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; import java.awt.event.MouseEvent; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import javax.swing.JPanel; /** * * 类说明: * * @author 彭晨明 E-mail:[email protected] * * @version 创建时间:2012-2-1下午9:30:129 * */ public class DrawPanelListener extends java.awt.event.MouseAdapter { private javax.swing.ButtonGroup shapeGroup = LeftPanel.getButtonGroup(); private Graphics g = CenterPanel.obtainGraphics(); private javax.swing.JLabel leftLabel = FootPanel.getLeftLabel(), rightLabel = FootPanel.getRightLabel(); public Object object; public Color leftColor = java.awt.Color.BLACK, rightColor = java.awt.Color.WHITE; private String shapeSelected; private int x0, y0, x1, y1, x2, y2, x3, y3, xa, ya, n = 0, clickcount = 0; private javax.swing.JPanel drawPanel; private Robot rb; private int[][] pointArray; private Color[][] pointArray1; public DrawPanelListener(javax.swing.JPanel drawPanel) { this.drawPanel = drawPanel; } public void mousePressed(MouseEvent e) { if (e.getButton() == 1) { g.setColor(leftLabel.getBackground()); } if (e.getButton() == 3) { g.setColor(rightLabel.getBackground()); } shapeSelected = shapeGroup.getSelection().getActionCommand(); object = e.getSource(); if (object instanceof JPanel) { if (n == 0) { x0 = e.getX(); y0 = e.getY(); } x1 = e.getX(); y1 = e.getY(); clickcount = e.getClickCount(); if (shapeSelected.equals("pencil")) { g.drawLine(x1, y1, x0, y0); } if (shapeSelected.equals("brush")) { int width = 0; String str = shapeGroup.getSelection().getActionCommand(); if (str.equals("bigOval")) { width = 5; } else if (str.equals("bigRect")) { width = 8; } Line2D.Double line2D = new Line2D.Double(x1, y1, x1, y1); BasicStroke basicStroke = new BasicStroke(width, 1, 1); Graphics2D g1 = (Graphics2D) g; g1.setStroke(basicStroke); g1.draw(line2D); } } } public void mouseDragged(MouseEvent e) { if (object instanceof JPanel) { x3 = e.getX(); y3 = e.getY(); if (shapeSelected.equals("pencil")) { pencil(); } if (shapeSelected.equals("airbrush")) { } if (shapeSelected.equals("brush")) { brush(); } } } public void mouseReleased(MouseEvent e) { if (object instanceof JPanel) { x2 = e.getX(); y2 = e.getY(); drawShape(); } savePoint(); } public void drawShape() { if (shapeSelected.equals("clip")) { } if (shapeSelected.equals("line")) { g.drawLine(x1, y1, x2, y2); } if (shapeSelected.equals("rect")) { g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); } if (shapeSelected.equals("oval")) { g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); } if (shapeSelected.equals("polygon")) { polygon(); } } public void polygon() { if (clickcount == 1) { if (n == 0) { g.drawLine(x1, y1, x2, y2); xa = x2; ya = y2; } if (n > 0) { g.drawLine(xa, ya, x1, y1); xa = x1; ya = y1; } n++; } if (clickcount == 2) { g.drawLine(x0, y0, x1, y1); n = 0; } } public void pencil() { g.drawLine(x1, y1, x3, y3); x1 = x3; y1 = y3; } public void brush() { int width = 0; Line2D.Double line2D = new Line2D.Double(x1, y1, x3, y3); String str = shapeGroup.getSelection().getActionCommand(); if (str.equals("bigOval")) { width = 5; } else if (str.equals("bigRect")) { width = 8; } BasicStroke basicStroke = new BasicStroke(width, 1, 1); Graphics2D g1 = (Graphics2D) g; g1.setStroke(basicStroke); g1.draw(line2D); x1 = x3; y1 = y3; } public void savePoint() { if (pointArray == null) { pointArray = new int[drawPanel.getHeight()][drawPanel.getWidth()]; } if(pointArray1 == null){ pointArray1 = new Color[drawPanel.getHeight()][drawPanel.getWidth()]; } Point point = drawPanel.getLocationOnScreen(); Dimension di_drawRect = new Dimension(drawPanel.getWidth(), drawPanel.getHeight()); Rectangle drawRect = new Rectangle(point, di_drawRect); try { if (rb == null) { rb = new Robot(); } BufferedImage image = rb.createScreenCapture(drawRect); for (int i = 0; i < pointArray.length; i++) { for (int j = 0; j < pointArray[i].length; j++) { pointArray[i][j] = image.getRGB(j, i); pointArray1[i][j] = new Color(image.getRGB(j, i)); } } CenterPanel.setPointArray(pointArray); CenterPanel.setPointArray1(pointArray1); } catch (Exception ef) { ef.printStackTrace(); } } }
3.选择颜色监听器:
package finalDraw; import java.awt.Color; import java.awt.Graphics; import java.awt.event.MouseEvent; /** * * 类说明: * * @author 彭晨明 E-mail:[email protected] * * @version 创建时间:2012-2-1下午8:52:59 * */ public class FootPanelColorListener extends java.awt.event.MouseAdapter { private javax.swing.JLabel leftLabel, rightLabel; public FootPanelColorListener(javax.swing.JLabel leftLabel, javax.swing.JLabel rightLabel) { this.leftLabel = leftLabel; this.rightLabel = rightLabel; } public void mousePressed(MouseEvent e) { if (e.getComponent() instanceof javax.swing.JLabel) { javax.swing.JLabel object = (javax.swing.JLabel) e.getComponent(); if (e.getButton() == 1) { Color leftColor = object.getBackground(); leftLabel.setBackground(leftColor); } else if (e.getButton() == 3) { Color rightColor = object.getBackground(); rightLabel.setBackground(rightColor); } } }
心路成长:
1凡事首先要想到是否自己就可以解决。培养自己查找资料的能力。
2 培养自己的商业思维,程序不是只写给自己看的,所以必须注意它的可读性。
3 做事不要总是只想而不去动手实践,那么成功的可能性就会大大降低。
4 成功的办法很简单,就是踏踏实实的做。
5 画图板是我来到蓝杰学习的第一个项目,前后左右差不多历时了3个月的时间。说实话,当初什么都不懂,什么都是张口闭口希望龙哥的帮忙,遇到不懂了就希望有谁可以来帮我,并且总是希望可以快点完成任务。所以开始学的很浮躁,后来发现这样子下去,什么都不能学到。真的是很感谢龙哥,想来还是可笑,刚刚来的时,觉得龙哥太严厉了,总是问他题目的时候,他总是要我自己去解决问题,我还心里怪他。但是现在真的是慢慢地明白了龙哥的良苦用心,如果不是这样,那我还不是和以前一样,做事总是喜欢依赖于别人。于是就这样在蓝杰这个强人如云的环境中成长。从实现一个窗体,一个菜单栏,一个标签,一个形状,一个监听器,一步一个脚印,就像我有个朋友说了一句话:虽然我走的很慢,但是我从不后退。亲,如果你真的想要做好一件事的话,请不要着急,慢慢来,一天天都往前走,其实你会比谁都走的快!
<!--EndFragment--><!--EndFragment--><!--EndFragment--><!--EndFragment-->
<!--EndFragment-->