1.SplitPicture.java 支持鼠标单击,键盘方向键移动 支持智能检测完成 package ui; import image.ImageCutter; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.swing.ImageIcon; import javax.swing.JPanel; /** * 图片拼图组件 * @author dmj * @since 2010/11/15 */ public class SplitPicture extends JPanel { private static final long serialVersionUID = -6379869983333972178L; private Image srcPic=null;//要显示的图片切片源 private ImageCutter picCutter=null;//图片剪裁类 private CutterImage[] cutterPics=null;//剪裁的切片类数组 private int rows=3,cols=3;//行数列数 private int cellspacing=1;//切片间的间距 private SplitPictureListener spl=null;//拼图动作监听器 /** * 获取面板的宽度 */ @Override public int getWidth(){ return (int)(picCutter.getSize().getWidth()); } /** * 获取面板的高度 */ @Override public int getHeight(){ return (int)(picCutter.getSize().getHeight()); } public SplitPicture(){ this.addKeyListener(new SplitPictureKeyListener()); this.addMouseListener(new SplitPictureMouseListener()); this.setFocusable(true); this.addSplitPictureListener(new SplitPictureListener(){ @Override public void completed(){} @Override public void moved() {} @Override public void moving() {} }); } public SplitPicture(Image src){ this(src,3,3); } /** * @param src 要剪裁成切片的图片源 */ public SplitPicture(Image src,int cols,int rows){ this(); this.srcPic=src; this.setCols(cols); this.setRows(rows); updateSplitPicture(); } /** * 更新切片初始化切片 */ public void updateSplitPicture(){ picCutter=new ImageCutter(srcPic); cutterPics=convertImage(picCutter.cut(getCols(), getRows())); setSplitPics(rows*cols); showComplete=false; repaint(); } /** * 拼图是否完成 * @return */ public boolean isComplete(){ boolean complete=true; for(int i=0;i<cols*rows;i++){ if(this.getCutterPics()[i]!=null &&this.getCutterPics()[i].partIndex!=i){ complete=false; break; } } return complete; } /** * 作弊排列 */ public void cheat(){ for(int i=0;i<cols*rows;i++){ int index=-1; for(int j=0;j<cols*rows;j++){ if(getCutterPics()[j]!=null && getCutterPics()[j].partIndex==i)index=j; } if(index!=-1 && !isComplete()){ move(i,index); } } } /** * 从Image类型转化为CutterImage类型 * @param imgs * @return */ private CutterImage[] convertImage(Image[] imgs){ CutterImage[] cutterImgs=new CutterImage[imgs.length]; for(int i=0;i<imgs.length;i++){ cutterImgs[i]=new CutterImage(imgs[i],i); } return cutterImgs; } /** * 随机排列切片图片顺序 * @param picNum 随机获取的切片数量 * @return */ private CutterImage[] setSplitPics(int picNum){ List<Integer> picLoaded=new ArrayList<Integer>(); Random rd=new Random(); CutterImage[] splitPics=new CutterImage[picNum]; while(picLoaded.size()!=picNum){ int temp=rd.nextInt(picNum); if(!picLoaded.contains(Integer.valueOf(temp))){ splitPics[picLoaded.size()]=this.getCutterPics()[temp]; picLoaded.add(temp); } } splitPics[splitPics.length-1]=null; return this.cutterPics=splitPics; } /** * 绘制剪裁好的切片 * @param g * @param showCutterPics */ protected void paintSplitPicture(Graphics g,CutterImage[] showCutterPics){ Color c=g.getColor(); g.setColor(Color.WHITE); g.fillRect(0, 0, getWidth(), getHeight()); for(int i=0;i<showCutterPics.length;i++){ CutterImage pic=showCutterPics[i]; if(pic==null)continue;//空的切片跳过 int w=pic.getWidth(); int h=pic.getHeight(); g.drawImage(pic.getCutterImage(), i%rows*(w+cellspacing),i/cols*(h+cellspacing) ,this); } g.setColor(c); } public void paintCompletePicture(Graphics g){ Color c=g.getColor(); g.setColor(Color.WHITE); g.fillRect(0, 0, getWidth(), getHeight()); g.drawImage(getSrcPic(), 0, 0, this); g.setColor(c); } /** * 显示拼图成功后的完整图片 */ public void showComplete(){ showComplete=true; repaint(); } private boolean showComplete=false;//是否显示完整图片 /** * 重写父类绘制页面方法 */ @Override public void paintComponent(Graphics g){ Image off=new BufferedImage(this.getWidth(),this.getHeight(),BufferedImage.TYPE_INT_RGB); Graphics dg=off.getGraphics();//双缓冲绘制 if(!showComplete)paintSplitPicture(dg,getCutterPics()); else paintCompletePicture(dg); g.drawImage(off,0,0,this.getWidth(),this.getHeight(),this); } /** * 判断当前鼠标所在的切片是否可以移动及移动的方向 * @param currentIndex 当前鼠标所在的切片索引 * @return */ public void judgeMove(int currentIndex){ if(currentIndex<0 || currentIndex>cols*rows)return; int l=currentIndex%cols==0?currentIndex:currentIndex-1; if(l!=currentIndex && getCutterPics()[l]==null){left(currentIndex);return;} int r=(currentIndex+1)%cols==0?currentIndex:currentIndex+1; if(r!=currentIndex && getCutterPics()[r]==null){right(currentIndex);return;} int t=currentIndex/rows==0?currentIndex:currentIndex-cols; if(t!=currentIndex && getCutterPics()[t]==null){up(currentIndex);return;} int b=currentIndex/rows==(rows-1)?currentIndex:currentIndex+cols; if(b!=currentIndex && getCutterPics()[b]==null){down(currentIndex);return; } } /** * 更新切片图片数组顺序 */ @Override public void move(int currentIndex,int nextIndex){ CutterImage temp=getCutterPics()[currentIndex]; getCutterPics()[currentIndex]=getCutterPics()[nextIndex]; getCutterPics()[nextIndex]=temp; spl.moving(); repaint(); spl.moved(); if(isComplete())spl.completed(); } /** * 当前索引为currentIndex的切片向上移动 * @param currentIndex */ public void up(int currentIndex){ int nextIndex=currentIndex/rows==0?currentIndex:currentIndex-cols; move(currentIndex,nextIndex); } /** * 当前索引为currentIndex的切片向下移动 * @param currentIndex */ public void down(int currentIndex){ int nextIndex=currentIndex/rows==(rows-1)?currentIndex:currentIndex+cols; move(currentIndex,nextIndex); } /** * 当前索引为currentIndex的切片向左移动 * @param currentIndex */ public void left(int currentIndex){ int nextIndex=currentIndex%cols==0?currentIndex:currentIndex-1; move(currentIndex,nextIndex); } /** * 当前索引为currentIndex的切片向右移动 * @param currentIndex */ public void right(int currentIndex){ int nextIndex=(currentIndex+1)%cols==0?currentIndex:currentIndex+1; move(currentIndex,nextIndex); } class SplitPictureMouseListener extends MouseAdapter{//鼠标监听器类 /** * 获取鼠标所在坐标的切片的索引 * @param p:鼠标所在的当前面板的坐标 */ private int getCurrentIndex(Point p){ int index=-1;//默认不存在索引 Rectangle rect=new Rectangle();//切片区域 for(int i=0;i<getCutterPics().length;i++){ if(getCutterPics()[i]==null)continue; int w=getCutterPics()[i].getWidth(); int h=getCutterPics()[i].getHeight(); rect.setBounds(i%rows*(w+cellspacing),i/cols*(h+cellspacing),w,h); if(rect.contains(p)){ index=i; break; } } return index; } /** * 鼠标按下事件 */ @Override public void mousePressed(MouseEvent event){ if(event.getButton()==MouseEvent.BUTTON1 ){ judgeMove(getCurrentIndex(event.getPoint())); }else if(event.isAltDown() && event.isControlDown()){ cheat(); repaint(); } } } class SplitPictureKeyListener implements KeyListener{//键盘监听器 /** * 定位空切片图片在cutterPics中的索引 * @return 索引 */ private int getBlankCutterIndex(){ int index=0; for(int i=0;i<getCutterPics().length;i++){ if(getCutterPics()[i]==null){ index= i; break; } } return index; } @Override public void keyPressed(KeyEvent event) {//键盘按键按下时 int code=event.getKeyCode(); if(code==KeyEvent.VK_DOWN ||code==KeyEvent.VK_KP_DOWN ){ up(getBlankCutterIndex());//上移空白切片 }else if(code==KeyEvent.VK_UP ||code==KeyEvent.VK_KP_UP ){ down(getBlankCutterIndex()); }else if(code==KeyEvent.VK_LEFT||code==KeyEvent.VK_KP_LEFT ){ right(getBlankCutterIndex()); }else if(code==KeyEvent.VK_RIGHT ||code==KeyEvent.VK_KP_RIGHT ){ left(getBlankCutterIndex()); } } @Override public void keyReleased(KeyEvent event) {} @Override public void keyTyped(KeyEvent arg0) {} } /** * 添加拼图监听器 * @param listener */ public void addSplitPictureListener(SplitPictureListener listener){ this.spl=listener; } /** * 移除拼图监听器 */ public void removeSplitPictureListener(){ this.spl=new SplitPictureListener(){ @Override public void completed() {} @Override public void moved() {} @Override public void moving() {} }; } public interface SplitPictureListener{//拼图监听器类 //拼图完成的时候 public void completed(); //正在移动拼图切片时 public void moving(); //移动拼图切片后 public void moved(); } class CutterImage {//剪裁后的切片类 private ImageIcon cutterImage;//该切片图像 private Integer partIndex;//该切片的剪裁索引 public CutterImage(){} public CutterImage(Image img,Integer index){ cutterImage=new ImageIcon(img); partIndex=index; } public int getWidth(){ return cutterImage.getIconWidth(); } public int getHeight(){ return cutterImage.getIconHeight(); } public Image getCutterImage() { return cutterImage.getImage(); } public void setCutterImage(Image cutterImage) { this.cutterImage = new ImageIcon(cutterImage); } public Integer getPartIndex() { return partIndex; } public void setPartIndex(Integer partIndex) { this.partIndex = partIndex; } } /** * 获取源图 * @return 源图Image类型 */ public Image getSrcPic() { return srcPic; } /** * 设置拼图源图 * @param srcPic 拼图源图 */ public void setSrcPic(Image srcPic) { this.srcPic = srcPic; updateSplitPicture(); } /** * 获取图片剪裁对象 * @return */ public ImageCutter getPicCutter() { return picCutter; } /** * 获取所有拼图切片数组 * @return */ CutterImage[] getCutterPics() { return cutterPics; } /** * 获取行数 * @return */ public int getRows() { return rows; } /** * 设置行数 * @param rows */ public void setRows(int rows) { this.rows = rows; } /** * 获取列数 * @return */ public int getCols() { return cols; } /** * 设置列数 * @param cols */ public void setCols(int cols) { this.cols = cols; } /** * 获取切片间距 * @return int */ public int getCellspacing() { return cellspacing; } /** * 设置切片间距 * @param cellspacing */ public void setCellspacing(int cellspacing) { this.cellspacing = cellspacing; updateSplitPicture(); } } 2.ImageCutter.java package image; import java.awt.Component; import java.awt.Dimension; import java.awt.Image; import java.awt.Toolkit; import java.awt.image.CropImageFilter; import java.awt.image.FilteredImageSource; import javax.swing.ImageIcon; /** * 图像剪裁类 * @author dmj * @since 2010/10/21 */ public class ImageCutter { private Image image;//裁剪的图片 public ImageCutter(){} public ImageCutter(Image img){this.image=img;} public Dimension getSize(){ ImageIcon temp=new ImageIcon(getImage()); return new Dimension(temp.getIconWidth(),temp.getIconHeight()); } /** * 裁剪图片(x,y)开始的矩形 * @param x * @param y * @param width * @param height * @return */ public Image cut(int x,int y,int width,int height) { CropImageFilter cif = new CropImageFilter(x,y,width,height); return Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cif)); } public Image cut(int x,int y,int width,int height,Component com) { CropImageFilter cif = new CropImageFilter(x,y,width,height); return com.createImage(new FilteredImageSource(image.getSource(),cif)); } /** * 剪裁xNum*yNum块 * @param xNum:列 * @param yNum:行 * @return */ public Image[] cut(int xNum,int yNum) { ImageIcon temp=new ImageIcon(getImage()); int width =temp.getIconWidth(); int height =temp.getIconHeight(); int cW=width/xNum;//每块宽度 int cH=height/yNum;//每块高度 Image[] cuts=new Image[xNum*yNum]; int index=0; for(int i=0;i<xNum;i++) { for(int j=0;j<yNum;j++) { cuts[index++]=cut(j*cW,i*cH,cW,cH); } } return cuts; } public Image getImage() { return image; } public void setImage(Image img) { this.image = img; } }