用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;
}
同样的是插入文字也要用数组保存 所有输入的文字