用JAVA做仿XP画图板 ,前前后后可以算是做了三次,现在做了个半成品产品出来,现在贴出第一个版本的核心代码 也把开发过程中遇到的问题写下了 画图板还会继续做 到时候会更新内容 欢迎交流 欢迎拍砖
在开发画图板的过程中 ,遇到的最大问题就是如何把绘画的各种不同图形 保存下来
在我的第一个画图板版本中 我是用一个定义了一个图形类 Drawing 他有若干个子类(直线 矩形 椭圆等等),
然后我定义了一个Drawing[] 数组,itemList 。 每次在鼠标释放时添加一个Drawing对象到itemlist数组中,在paint方法中 对itemlist数组遍历 绘画存在其中的所有图形。
贴个截图
以下是代码(画布)DrawPanel,和Drawing类的代码
DrawPanel
import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.awt.event.MouseMotionAdapter; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.util.Random; //绘图区类(各种图形的绘制和鼠标事件) public class DrawPanel extends JPanel { Drawing[] itemList = new Drawing[5000];; // 绘制图形类 BottomToolBar bottombar; BottomPanel bottomPanel; int index = 0;// 当前已经绘制的图形数目 Random rd = new Random();// 喷雾的随机点生成器 int reSize=0;//用于设置拖动事件是否改变panel大小 public DrawPanel() { setBackground(Color.white);// 设置绘制区的背景是白色 addMouseListener(new MouseListener());// 添加鼠标事件 addMouseMotionListener(new MouseMotion()); createNewitem(); } /** * 将JFrame的下部面板工具栏传递给DrawPanel * @param bottombar */ public void setBar(BottomToolBar bottombar) { this.bottombar=bottombar; } /** * 将下部信息面板传递个DrawPanel * @param bottomPanel */ public void setBottomPanel(BottomPanel bottomPanel) { this.bottomPanel=bottomPanel; } /** * 画图方法 */ public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g;// 定义随笔画 int j = 0; //g2d.drawImage(Save4Bit.img, null, 0, 0); if(DrawSet.img!=null) g2d.drawImage(DrawSet.img,null,0,0 ); while (j <= index) { //System.out.println("this is repaint"); itemList[j].draw(g2d); j++; } } // 新建一个图形的基本单元对象的程序段 public void createNewitem() { //System.out.println(DrawSet.drawTool); switch (DrawSet.drawTool) { case 2: itemList[index] = new Rubber(); break; case 4: itemList[index] = new TiQu(); break; case 6: itemList[index] = new Pencil(); break; case 8: itemList[index] = new PenWu(); break; case 9: itemList[index] = new Word(); System.out.println("创建>>>9"); break; case 10: itemList[index] = new Line(); break; case 12: itemList[index] = new Rect(); break; case 14: itemList[index] = new Oval(); break; case 15: itemList[index] = new RoundRect(); break; } } // TODO 鼠标事件MouseA类继承了MouseAdapter // 用来完成鼠标的响应事件的操作 class MouseListener extends MouseAdapter { public void mousePressed(MouseEvent me) { itemList[index].strokeWidth = DrawSet.strokeWidth; itemList[index].x1 = itemList[index].x2 = me.getX(); itemList[index].y1 = itemList[index].y2 = me.getY(); // 判断是鼠标左键还是右键设置颜色 int clickCount = me.getButton(); if (clickCount == 1) itemList[index].pColor = DrawSet.drawColor1; if (clickCount == 3) itemList[index].pColor = DrawSet.drawColor2; // 如果当前选择为随笔画或橡皮擦 ,则进行下面的操作 if (DrawSet.drawTool == 6 || DrawSet.drawTool == 2) { itemList[index].x1 = itemList[index].x2 = me.getX(); itemList[index].y1 = itemList[index].y2 = me.getY(); } if (DrawSet.drawTool == 8) { int r = (int) (DrawSet.strokeWidth + 2) * 5; int pointNumber = (r * 2); itemList[index].r1 = new int[pointNumber]; itemList[index].r2 = new int[pointNumber]; itemList[index].pointNumber = pointNumber; for (int i = 0; i < pointNumber; i++) { itemList[index].r1[i] = rd.nextInt(r) - r; itemList[index].r2[i] = rd.nextInt(r) - r; } } // 如果当前选中的是输入文字 else if (DrawSet.drawTool == 9) { itemList[index].str=JOptionPane.showInputDialog(null, "请输入文字"+index);//这里设置了str itemList[index].x1 = me.getX(); itemList[index].y1 = me.getY(); index++; createNewitem();// 创建新的图形的基本单元对象 repaint(); } else if(DrawSet.drawTool == 4)//提取 { int x = me.getXOnScreen(); int y = me.getYOnScreen(); // System.out.println("ScreenX: "+x+" ScreenY: "+y); // System.out.println("X: "+me.getX()+" Y: "+me.getY()); Robot robot; try { robot = new Robot(); //要用就绝对坐标 这是另一种获取颜色的方法 // int c = 0; // Rectangle screenRect = new Rectangle(x,y, 1,1); // BufferedImage img=robot.createScreenCapture(screenRect); // c=img.getRGB(0, 0); // bottombar.setFirstLabel(new Color(c));//设置下部颜色显示面板 Color c=robot.getPixelColor(x,y);//x y 为屏幕绝对坐标 bottombar.setFirstLabel(c); DrawSet.drawColor1=c; } catch (AWTException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void mouseReleased(MouseEvent me) { repaint(); index++; createNewitem();// 创建新的图形的基本单元对象 DrawPanel.this.bottomPanel.hwLabel.setText(""); } } // 鼠标事件MouseB继承了MouseMotionAdapter // 用来处理鼠标的滚动与拖动 class MouseMotion extends MouseMotionAdapter { public void mouseDragged(MouseEvent me)// 鼠标的拖动 { if(reSize==1) { me.getX(); me.getY(); DrawPanel.this.setSize(me.getX(), me.getY()); return ; } //显示信息 int showW=Math.abs(itemList[index].x2 - itemList[index].x1); int showH=Math.abs(itemList[index].y2 - itemList[index].y1); DrawPanel.this.bottomPanel.hwLabel.setText(showW+" , "+showH); //画图 if (DrawSet.drawTool == 6 || DrawSet.drawTool == 2) { // // 为什么这里断断续续的 // itemList[index].x2 = itemList[index].x1 =me.getX(); // itemList[index].y2 = itemList[index].y1 = me.getY(); itemList[index].x1 = itemList[index].x2; itemList[index].y1 = itemList[index].y2; itemList[index].x2 = me.getX(); itemList[index].y2 = me.getY(); } else { itemList[index].x2 = me.getX(); itemList[index].y2 = me.getY(); } repaint(); } /** * 判断鼠标是否在画布边缘 * @param x * @param y * @return */ public boolean isDrag(int x,int y) { int rightX=(int)(DrawPanel.this.getWidth()+DrawPanel.this.getBounds().getX()); int bottomY=(int)(DrawPanel.this.getHeight()+DrawPanel.this.getBounds().getY()); if(Math.abs(x-rightX)<10&&Math.abs(y-bottomY)<10) return true; return false; } public boolean isInPanel(int x,int y) { if(x>=0&&x<DrawPanel.this.getWidth()&&y>=0&&y<DrawPanel.this.getHeight()) return true; return false ; } public void mouseMoved(MouseEvent e) { int x=e.getX(); int y=e.getY(); DrawPanel.this.bottomPanel.pointLabel.setText("X: "+x+" Y: "+y); //重大错误 if(!isInPanel(x,y)) { System.out.println("out"); try { Robot robot=new Robot(); Rectangle rec=new Rectangle(0,0,DrawPanel.this.getWidth(),DrawPanel.this.getHeight()); DrawSet.img=robot.createScreenCapture(rec); } catch (AWTException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } else { System.out.println("in"); } //Cursor cursor=DrawPanel.this.getCursor(); if(isDrag(x,y)) { DrawPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)); reSize=1; } else { DrawPanel.this.setCursor(DrawSet.cursorIcon); reSize=0; } }//move方法结束 }//监听事件结束 }
Drawing
import java.awt.AWTException; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Robot; import java.awt.geom.Line2D; import java.awt.geom.Line2D.Double; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.io.Serializable; //图形绘制类 用于绘制各种图形 //父类,基本图形单元,用到串行的接口,保存使用到 //公共的属性放到超类中,子类可以避免重复定义 import java.util.ArrayList; import java.util.Random; /*类通过实现 java.io.Serializable 接口以启用其序列化功能。 未实现此接口的类将无法使其任何状态序列化或反序列化。 可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段, 仅用于标识可序列化的语义。*/ public class Drawing implements Serializable { int x1, x2, y1, y2; // 定义坐标属性 public Color pColor;// =DrawSet.drawColor1; //定义色彩属性 Line2D pLine;//临时的Line float strokeWidth;//画笔宽度 String str=null;//写文字 Random rd = new Random();//喷雾的随机数 int r1[], r2[];//喷雾的各点半径 int pointNumber;//喷雾生产点的个数 static Robot robot; ArrayList<Line2D> pLines = new ArrayList<Line2D>();//用来存随笔画的线 public static BufferedImage img; void draw(Graphics2D g2d) { }// 定义绘图函数 } class Line extends Drawing// 直线类 { void draw(Graphics2D g2d) { g2d.setPaint(pColor);// 为 Graphics2D 上下文设置 Paint 属性。 g2d.setStroke(new BasicStroke(strokeWidth)); g2d.drawLine(x1, y1, x2, y2);// 画直线 } } class Rect extends Drawing {// 矩形类 void draw(Graphics2D g2d) { g2d.setStroke(new BasicStroke(strokeWidth)); g2d.setPaint(pColor); g2d.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1), Math.abs(y2 - y1)); } } class fillRect extends Drawing {// 实心矩形类 void draw(Graphics2D g2d) { g2d.setPaint(pColor); g2d.fillRect(Math.min(x1, x2), Math.min(y2, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); } } class Oval extends Drawing {// 椭圆类 void draw(Graphics2D g2d) { g2d.setStroke(new BasicStroke(strokeWidth)); g2d.setPaint(pColor); g2d.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); } } class fillOval extends Drawing {// 实心椭圆类 void draw(Graphics2D g2d) { g2d.setPaint(pColor); g2d.fillOval(Math.min(x1, x2), Math.min(y2, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); } } class Circle extends Drawing {// 矩形类 void draw(Graphics2D g2d) { g2d.setStroke(new BasicStroke(strokeWidth)); g2d.setPaint(pColor); g2d.drawOval(Math.min(x1, x2), Math.min(y2, y2), Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2)), Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2))); } } class fillCircle extends Drawing {// 实心圆类 void draw(Graphics2D g2d) { g2d.setPaint(pColor); g2d.fillOval(Math.min(x1, x2), Math.min(y2, y2), Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2)), Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2))); } } class RoundRect extends Drawing {// 圆角矩形类 void draw(Graphics2D g2d) { g2d.setStroke(new BasicStroke(strokeWidth)); g2d.setPaint(pColor); g2d.drawRoundRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2), 50, 35); } } class fillRoundRect extends Drawing {// 实心圆角矩形类 void draw(Graphics2D g2d) { g2d.setPaint(pColor); g2d.fillRoundRect(Math.min(x1, x2), Math.min(y2, y2), Math.abs(x1 - x2), Math.abs(y1 - y2), 50, 35); } } class Pencil extends Drawing {// 随笔画类 void draw(Graphics2D g2d) { g2d.setStroke(new BasicStroke(strokeWidth)); pLine = new Line2D.Double(x1, y1, x2, y2); pLines.add(pLine); g2d.setPaint(pColor); for (Line2D tpLine : pLines) g2d.draw(tpLine); } } class Rubber extends Drawing {// 橡皮擦类 void draw(Graphics2D g2d) { g2d.setPaint(new Color(255, 255, 255));// 白色 pLine = new Line2D.Double(x1, y1, x2, y2); pLines.add(pLine); g2d.setStroke(new BasicStroke(5.0f)); for (Line2D tpLine : pLines) g2d.draw(tpLine); } } class PenWu extends Drawing {//喷雾类 void draw(Graphics2D g2d) { g2d.setPaint(pColor); g2d.setStroke(new BasicStroke(1.0f)); for (int i = 0; i < pointNumber; i++) { int x0 = x1 + r1[i]; int y0 = y1 + r2[i]; g2d.drawLine(x0, y0, x0, y0); } } } class Word extends Drawing {// 输入文字类 void draw(Graphics2D g2d) { g2d.setPaint(pColor); if(str!=null) g2d.drawString(str, x1, y1); } } /** * 提取类实际上是空的 其功能在DrawPanel中实现 * @author ZhangZunC * */ class TiQu extends Drawing { }
开发过程中遇到的问题:(原问题代码没保存下来 所以以下内容 看起来可能会不明所以)
1.在绘画喷雾的时候 发现每次一个repaint操作以画好的喷雾的点会再次随机绘画(喷雾的实现是随机产生若干个点 然后绘画出来)弄了半天 在龙哥的帮助下 才发现我每次新建一个图像后 对会调用Drawing类的draw方法 ,每次都会产生新的随机数 所以每次repaint,已经画好的喷雾都会再次随机
找到问题后解决起来就简单了,直接用了一个数组来保存每个喷雾对象已产生的随机点
itemList[index].r1 = new int[pointNumber]; itemList[index].r2 = new int[pointNumber]; itemList[index].pointNumber = pointNumber; for (int i = 0; i < pointNumber; i++) { itemList[index].r1[i] = rd.nextInt(r) - r; itemList[index].r2[i] = rd.nextInt(r) - r; }
同样的是插入文字也要用数组保存 所有输入的文字