package com.vci.client.portal.Formdesign; import java.awt.AlphaComposite; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import com.vci.client.portal.Formdesign.object.ObjectUtil; /** * 实现组件拖拽的类 * * 参考swing hacks * * @author liudi * */ public class ControlDragManager extends Object { private JFrame frame; private JComponent target; private ControlGhostGlassPane glass = null; private Component dragSource; public static final Image right_img = ObjectUtil.getImage("right.png"); public static final Image wrong_img = ObjectUtil.getImage("wrong.png"); /** * @param frame * 参数frame为要实现拖拽的frame,frame中一定只能有一个DragManage对象 ,
* 如果有多个,就会导致冲突。
* 如果该窗口要实现拖拽功能,必须有一个DragManage对象,
* * @param target * 拖拽目标 */ public ControlDragManager(JFrame frame, JComponent target) { this.frame = frame; this.target = target; // target.setLayout(null); this.frame.setGlassPane(this.glass = new ControlGhostGlassPane()); } /** * 指定能拖拽的组件 * * * @param souce * 被拖拽的组件 */ public void canDrag(Component source) { DragAction action = null; action = new DragAction(glass, target); source.addMouseListener(action); source.addMouseMotionListener(action); dragSource = source; } /** * 返回拖拽源对象 * * @return */ public Component getDragSource() { return dragSource; } /** * 用来画图形做跨组件的视觉效果的面板 * * */ static class ControlGhostGlassPane extends JPanel { private static final long serialVersionUID = 1L; private AlphaComposite composite; private BufferedImage dragged = null; private int state; private Point location = new Point(0, 0); public static final int STATE_ACCEPT = 1; public static final int STATE_UNACCEPT = 2; public static final int STATE_NOMAR = -1; public ControlGhostGlassPane() { setOpaque(false); // 半透明效果 composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); } public void setState(int state) { this.state = state; } public void setImage(BufferedImage dragged) { this.dragged = dragged; } public void setPoint(Point location) { this.location = location; } public void paintComponent(Graphics g) { if (dragged == null) { return; } // 在蒙版上画图 int x = (int) (location.getX() - (dragged.getWidth(this) / 2)); int y = (int) (location.getY() - (dragged.getHeight(this) / 2)); Graphics2D g2 = (Graphics2D) g; g2.setComposite(composite); g2.drawImage(dragged, x, y, null); switch (state) { case STATE_ACCEPT: g2.drawImage(right_img, x + dragged.getWidth(this), y, this); break; case STATE_UNACCEPT: g2.drawImage(wrong_img, x + dragged.getWidth(this), y, this); break; case STATE_NOMAR: break; } } } /** * 拖拽动作 * * @author liudi * */ class DragAction implements MouseMotionListener, MouseListener { private ControlGhostGlassPane glassPane; private JComponent targetComp; private boolean flag; public DragAction(ControlGhostGlassPane glassPane, JComponent targetComp) { this.glassPane = glassPane; this.targetComp = targetComp; flag = false; } public void mouseDragged(MouseEvent e) { flag = true; Component c = e.getComponent(); Point p = (Point) e.getPoint().clone(); SwingUtilities.convertPointToScreen(p, c); Point eventPoint = (Point) p.clone(); SwingUtilities.convertPointFromScreen(p, glassPane); // 鼠标是否在目标控件的上方 SwingUtilities.convertPointFromScreen(eventPoint, targetComp); int state = targetComp.contains(eventPoint) ? ControlGhostGlassPane.STATE_ACCEPT : ControlGhostGlassPane.STATE_UNACCEPT; glassPane.setState(state); glassPane.setPoint(p); glassPane.repaint(); } public void mouseMoved(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { flag = false; Component c = e.getComponent(); BufferedImage image = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics g = image.getGraphics(); c.paint(g); glassPane.setVisible(true); Point p = (Point) e.getPoint().clone(); SwingUtilities.convertPointToScreen(p, c); SwingUtilities.convertPointFromScreen(p, glassPane); glassPane.setPoint(p); // glassPane.setImage(image); glassPane.repaint(); } public void mouseReleased(MouseEvent e) { if (!flag) { glassPane.setImage(null); glassPane.repaint(); glassPane.setVisible(false); glassPane.setImage(null); return; } ControlDragManager.this.dragSource = null; System.gc(); final Component c = e.getComponent(); final Point p = (Point) e.getPoint().clone(); SwingUtilities.convertPointToScreen(p, c); final Point eventPoint = (Point) p.clone(); SwingUtilities.convertPointFromScreen(p, glassPane); SwingUtilities.convertPointFromScreen(eventPoint, targetComp); glassPane.setPoint(p); glassPane.repaint(); /* * 移动控件有一下几种情况 * * 1、控件在原来的位置之上,没动 * * 2、控件从原来的位置移动到目标控件的位置 * * 3、控件已经在目标的位置上,然后自动在目标的位置 * * 4、控件在目标的位置上移动的其他控件上 */ // 还没有进入目标组件 if (!c.getParent().equals(targetComp) && !targetComp.contains(eventPoint)) { new Thread(new Runnable() { public void run() { // 没有接受 glassPane.setState(ControlGhostGlassPane.STATE_NOMAR); // 拿到组件的原始位置 Point cp = (Point) c.getLocationOnScreen().clone(); // 转成glass位置 SwingUtilities.convertPointFromScreen(cp, glassPane); // 当前组件在glass上的位置 int x = cp.x; int y = cp.y; // 拿到当前显示的图片的位置 int cx = p.x - (c.getWidth() / 2); int cy = p.y - (c.getHeight() / 2); int subX = (x - cx) / 10; int subY = (y - cy) / 10; x = p.x - (c.getWidth() / 2); y = p.y - (c.getHeight() / 2); for (int i = 0; i < 11; i++) { x += subX; y += subY; if (i == 10) { x = cp.x; y = cp.y; } cx = x + (c.getWidth() / 2); cy = y + (c.getHeight() / 2); glassPane.setPoint(new Point(cx, cy)); glassPane.repaint(); try { Thread.sleep(20); } catch (Exception e2) { e2.printStackTrace(); } } glassPane.setVisible(false); glassPane.setImage(null); } }).start(); return; } // 移动到目标的位置 if (!c.getParent().equals(targetComp) && targetComp.contains(eventPoint)) { // 复制出新的组件 Component obj = (Component) ObjectUtil.cloneObject(c); // 让他能拖动 ControlDragManager.this.canDrag(obj); // 添加到目标位置 targetComp.add(obj); Point p2 = (Point) e.getPoint().clone(); SwingUtilities.convertPointToScreen(p2, c); SwingUtilities.convertPointFromScreen(p2, targetComp); int x = p2.x - obj.getWidth() / 2; int y = p2.y - obj.getHeight() / 2; obj.setLocation(x, y); targetComp.repaint(); targetComp.updateUI(); glassPane.setVisible(false); glassPane.setImage(null); return; } // 控件已经在目标的位置上,然后自动在目标的位置 if (c.getParent().equals(targetComp) && targetComp.contains(eventPoint)) { Point p2 = (Point) e.getPoint().clone(); SwingUtilities.convertPointToScreen(p2, c); SwingUtilities.convertPointFromScreen(p2, targetComp); int x = p2.x - c.getWidth() / 2; int y = p2.y - c.getHeight() / 2; c.setLocation(x, y); targetComp.repaint(); glassPane.setVisible(false); glassPane.setImage(null); return; } // 控件在目标的位置上移动的其他控件上 if (c.getParent().equals(targetComp) && !targetComp.contains(eventPoint)) { // 没有接受 glassPane.setState(ControlGhostGlassPane.STATE_NOMAR); // 这里记录图形的 new Thread(new Runnable() { public void run() { // 组件在glass上的位置 Point cp = (Point) c.getLocationOnScreen().clone(); // 转成glass位置 SwingUtilities.convertPointFromScreen(cp, glassPane); // 拿到组件的位置 int x = cp.x; int y = cp.y; // 拿到当前鼠标的位置 int cx = eventPoint.x; int cy = eventPoint.y; int subX = (x - cx) / 10; int subY = (y - cy) / 10; x = eventPoint.x; y = eventPoint.y; for (int i = 0; i < 11; i++) { x += subX; y += subY; if (i == 10) { x = cp.x; y = cp.y; } cx = x + (c.getWidth() / 2); cy = y + (c.getHeight() / 2); glassPane.setPoint(new Point(cx, cy)); glassPane.repaint(); try { Thread.sleep(20); } catch (Exception e2) { e2.printStackTrace(); } } glassPane.setVisible(false); glassPane.setImage(null); } }).start(); } } } }