1

我已经在谷歌上搜索了几个小时,尝试了一百万种不同的细微变化,但都无济于事,所以我认为最好的选择是挑选比我更熟练的人的大脑。

我正在编写一个从数据库加载一堆按钮的类,目标是让用户能够根据自己的喜好排列按钮,但是,由于某种原因,我似乎无法让框架重新验证或重新粉刷。按钮会四处移动,但不会像我编码的那样重新排列。该组织似乎工作正常,即释放鼠标按钮时进行重新排列所涉及的代码,只是组件将仅停留在它们被拖放的位置,即使它们在各自的列表中重新排序。

代码很长,我不想发布整个课程,因为它可能会关闭一些人,但我不知道我在哪里犯了错误,所以我认为发布代码最符合我的利益整件事情。主要关注的领域是mouseReleased(MouseEvent e) {...}/repaint()方法refresh(),但是,我可能在其他地方遗漏了一些东西。

tl; dr:我基本上只是setBounds()在用户按照他们想要的顺序拖放按钮后尝试执行 a ,但按钮保持在它们被拖放的同一位置,并且不会revalidate()or repaint()。我什removeAll至无法清除组件面板并重新加载。

提前谢谢你。这是我的代码:

public class AdminButtonEditor extends javax.swing.JFrame {
    public AdminButtonEditor(OrderView parent) { ...
        ...
        Component[] components = buttonsPanel.getComponents();
        for (int i = 0; i < components.length; i++) {
            Component c = components[i];
            if (c instanceof JButton) {
                JButton jb = (JButton) c;
                jb.setFocusable(false);
                buttons.add(new MyJButton(...));
            }
        }
        for (int i = 0; i < buttons.size(); i++) {
            buttons.get(i).addTo(editPanel);
            buttons.get(i).orderIndex=modButtonList.get(i).menuModifier.getViewOrderValue();
            buttons.get(i).idx=i;
        }
        EventHandler eh = new EventHandler();
        addWindowListener(eh);
        editPanel.addMouseMotionListener(eh);
        editPanel.addMouseListener(eh);
        contentPane.add(editPanel, BorderLayout.CENTER);
    }
    protected void refresh() {
        if (!buttons.isEmpty() && buttons.get(0) != null) {
            contentPane.remove(editPanel);
            editPanel.removeAll();
            for (int i = 0; i < buttons.size(); i++) {
                MyJButton s = buttons.get(i);
                s.addTo(editPanel);
            }
            contentPane.add(editPanel, BorderLayout.CENTER);
            editPanel.repaint();
        }
    }
    public void paint(Graphics g) {
       refresh();
       super.paint(g);
    }
    private int getSelectionIndex(int x, int y) {
        int s=-1;
        for (int i=buttons.size()-1; i>=0;i--){
            if (buttons.get(i).contains(x, y)) {
                s = i;
                break;
            }
        }
        return s;
    }
private class EventHandler implements MouseInputListener,WindowListener, ActionListener {
    private int selectionIndex, startX, startY, lastX, lastY;
    private MyJButton selected;
    private boolean moving=false;
    ....
    ....
    public void mouseReleased(MouseEvent e) {
        if (moving){
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            moving=false;
            int dropX=e.getX();
            int dropY=e.getY();
            int row = dropY/selected.height;
            int col = dropX/selected.width;
            int idx=(row*3+col)-1;
            int oldIdx=buttons.indexOf(selected);
            insertIntoList(idx,oldIdx);
         }
        if (selected!=null){
            selected.unHighLight();
            selected=null;
        }

        Collections.sort(buttons);
        for (int i=0;i<buttons.size();i++){
        //modButtonList.get(buttons.get(i).idx).menuModifier.setViewOrderValue(buttons.get(i).orderIndex);
        }
        editPanel.validate();
        repaint();
    }

    private void insertIntoList(int idx, int oldIdx) {
        MyJButton temp = buttons.get(idx);
        int tempid=buttons.get(idx).idx;
        buttons.set(idx, new MyJButton(selected.text,selected.x,selected.y,selected.width,selected.height,selected.idx));
        buttons.get(idx).orderIndex=temp.orderIndex;
        if (idx<oldIdx){
            int id;
            for (int i=oldIdx;i>idx+1;i--){
                id=buttons.get(i).orderIndex;
                buttons.set(i, new MyJButton(buttons.get(i-1).text,buttons.get(i-1).x,buttons.get(i-1).y,buttons.get(i-1).width,buttons.get(i-1).height,buttons.get(i-1).idx));
                buttons.get(i).orderIndex=id;
            }
            id = buttons.get(idx+1).orderIndex;
            buttons.set(idx+1,new MyJButton(temp.text,temp.x,temp.y,temp.width,temp.height,temp.idx));
            buttons.get(idx+1).orderIndex=id;
        } else if (idx>oldIdx) {
            int id;
            for (int i=oldIdx;i<idx-1;i++){
                id=buttons.get(i).orderIndex;
                buttons.set(i, new MyJButton(buttons.get(i+1).text,buttons.get(i+1).x,buttons.get(i+1).y,buttons.get(i+1).width,buttons.get(i+1).height,buttons.get(i+1).idx));
                buttons.get(i).orderIndex=id;
            }
            id = buttons.get(idx-1).orderIndex;
            buttons.set(idx-1,new MyJButton(temp.text,temp.x,temp.y,temp.width,temp.height,temp.idx));
            buttons.get(idx-1).orderIndex=id;;
        } else {
            buttons.get(idx).x=buttons.get(idx).originx;
            buttons.get(idx).y=buttons.get(idx).originy;
        }
        repaint();
    }
    public void mouseDragged(MouseEvent e) {
        if (moving) {
            Graphics g = editPanel.getGraphics();
            g.setColor(Color.black);
            g.drawLine(selected.getXPos(), 0, selected.getXPos(),editPanel.getWidth());
            g.drawLine(0, selected.getYPos(), editPanel.getHeight(), selected.getYPos());
            selected.moveBy(e.getX()-lastX, e.getY()-lastY);
            g.setXORMode(Color.black);

            g.drawLine(selected.getXPos(), 0, selected.getXPos(), editPanel.getWidth());
            g.drawLine(0, selected.getYPos(), editPanel.getHeight(), selected.getYPos());

            lastX=e.getX();
            lastY=e.getY();
            repaint();
        }
    }
    ....
}
  private class MyJButton extends JButton implements Comparable {
    private int orderIndex,idx;
    private int x, y, width, height,originx,originy;
    private String text;
    public Border DEFAULT_BORDER;// new SoftBevelBorder(BevelBorder.RAISED);
    public Border SELECT_BORDER = BorderFactory.createLineBorder(Color.RED, 3, true);

    public MyJButton(String text, int x, int y, int width, int height) {
        ....
        setFocusable(false);
    }
    public MyJButton(String text, int x, int y, int width, int height,int idx) {....}

    public void addTo(JPanel p) {
        setBounds(x, y, width, height);
        p.add(this);
    }

    @Override
    public boolean contains(int x, int y) {
        int x1 = x, y1 = y;
        if (x1 >= this.x && y1 >= this.y && x1 <= this.x + width && y1 <= this.y + height) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void setSize(int w, int h) {
        width = w;
        height = h;
    }
    ....
    public void moveBy(int dx, int dy) {
        x += dx;
        y += dy;
    }

    @Override
    public void resize(int newWidth, int newHeight) {
        this.width = newWidth;
        this.height = newHeight;
        setBounds(x, y, width, height);
    }

    public int compareTo(Object o) {
        MyJButton mjb = (MyJButton)o;
        return this.idx-mjb.idx;
    }

  }
}
4

1 回答 1

3

+1 对 GagandeepBalis 的评论。

好的,所以我觉得这很酷,并决定进一步研究它。

我想出了一些让它工作所需的逻辑,也许不是最好的,但是......:

1)我们需要使我们JButton的 s 可拖动(谢谢@camickr 和他的DragLayout):)

2) 当一个JButtons 被拖拽而不是 ie on 时,mouseReleased(..)我们应该检查我们拖拽的按钮是否与其他按钮发生碰撞

3)我们通过获取 JButton 图像并计算我们拖动的 有JButton多少不透明像素覆盖另一个按钮来检查 a 是否与另一个碰撞。JButton

4)对碰撞次数进行排序并找到最高的,这将被使用,这样我们就可以看到在哪里插入JButton我们拖动的。即它将由碰撞最多的组件插入。

5)对持有按钮的按钮进行排序ArrayList以匹配更改

6)删除所有按钮并使用数组重新添加它们(因此它们将被重新排序)。

这是一个示例(大多数代码发生在被覆盖的ComponentMover mouseReleased(..)方法中):

在拖动任何东西之前:

在此处输入图像描述

将按钮 4 拖到按钮 1 上并松开鼠标按钮后:

在此处输入图像描述

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class DragButtons {

    ArrayList<JButton> buttons = new ArrayList<>();

    public DragButtons() {
        initComponents();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new DragButtons();
            }
        });
    }

    private void initComponents() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JPanel panel = new JPanel(new GridLayout(2, 2));

        ComponentMover cm = new ComponentMover() {
            @Override
            public void mouseReleased(MouseEvent e) {
                super.mouseReleased(e);
                HashMap<Integer, JButton> collisions = new HashMap<>();
                JButton draggedButton = (JButton) e.getSource();

                for (JButton btn : buttons) {//iterate through all buttons and get the number of collsions of each
                    if (btn != draggedButton) {//dont chck button we were dragging
                        int col = checkPerPixelCollision(draggedButton, btn);
                        System.out.println("Button " + btn.getText());
                        System.out.println(col);
                        collisions.put(col, btn);
                    }
                }
                //lets get the button which had most collisions
                int maxCollisions = 0;
                JButton intersectingButton = null;
                for (Map.Entry<Integer, JButton> entry : collisions.entrySet()) {
                    Integer collisionCount = entry.getKey();
                    JButton button = entry.getValue();
                    if (collisionCount > maxCollisions) {
                        maxCollisions = collisionCount;
                        intersectingButton = button;
                    }
                }

                boolean reLayout = false;

                if (maxCollisions > 0) {//check if there was any
                    System.out.println("Button " + draggedButton.getText() + " is intersecting more of Button " + intersectingButton.getText());
                    System.out.println("Collisions: " + maxCollisions);
                    reLayout = true;
                } else {
                    System.out.println("No change made");
                    reLayout = false;
                }

                ArrayList<JButton> tmpButtons = (ArrayList<JButton>) buttons.clone();//create clone of buttons

                if (reLayout) {//a button as moved and panel needs to be layed out
                    buttons.clear();//clear old buttons

                    for (JButton b : tmpButtons) {//re-order jbuttons
                        if (b == intersectingButton) {
                            buttons.add(draggedButton);
                        } else if (b == draggedButton) {
                            buttons.add(intersectingButton);
                        } else {
                            buttons.add(b);
                        }
                    }
                    panel.removeAll();//remove all buttons
                    for (JButton btn : buttons) {//iterate through all buttons and get the number of collsions of each
                        panel.add(btn);//re-add buttons according to arraylist
                    }
                    panel.revalidate();
                    panel.repaint();
                    //re-order the Array of buttons to fit
                    //remove all button and re add them using sorted array
                }

            }
        };

        for (int i = 0; i < 4; i++) {
            JButton b = new JButton(String.valueOf(i + 1));
            buttons.add(b);
            panel.add(b);
            cm.registerComponent(b);
        }

        frame.add(panel);

        frame.pack();
        frame.setVisible(true);

    }

    public HashSet<String> getMask(JButton e) {
        HashSet<String> mask = new HashSet<>();
        int pixel, a;
        BufferedImage bi = null;
        try {
            bi = componentToImage(e, e.getBounds()); //gets the current image being shown
        } catch (IOException ex) {
            Logger.getLogger(DragButtons.class.getName()).log(Level.SEVERE, null, ex);
        }
        for (int i = 0; i < bi.getWidth(); i++) { // for every (x,y) component in the given box, 
            for (int j = 0; j < bi.getHeight(); j++) {
                pixel = bi.getRGB(i, j); // get the RGB value of the pixel
                a = (pixel >> 24) & 0xff;
                if (a != 0) {  // if the alpha is not 0, it must be something other than transparent
                    mask.add((e.getX() + i) + "," + (e.getY() - j)); // add the absolute x and absolute y coordinates to our set
                }
            }
        }
        return mask;  //return our set
    }

    public static BufferedImage componentToImage(Component component, Rectangle region) throws IOException {
        BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
        Graphics g = img.getGraphics();
        g.setColor(component.getForeground());
        g.setFont(component.getFont());
        component.paintAll(g);
        ImageIO.write(img, "png", new File("c:/saved.png"));
        return img;
    }

    // Returns true if there is a collision between object a and object b   
    public int checkPerPixelCollision(JButton b, JButton b2) {
        // This method detects to see if the images overlap at all. If they do, collision is possible
        int ax1 = (int) b2.getX();
        int ay1 = (int) b2.getY();

        int ax2 = ax1 + (int) b2.getWidth();
        int ay2 = ay1 + (int) b2.getHeight();

        int bx1 = (int) b.getX();
        int by1 = (int) b.getY();

        int bx2 = bx1 + (int) b.getWidth();

        int by2 = by1 + (int) b.getHeight();

        if (by2 < ay1 || ay2 < by1 || bx2 < ax1 || ax2 < bx1) {
            return 0; // Collision is impossible.
        } else { // Collision is possible.
            // get the masks for both images
            HashSet<String> maskPlayer1 = getMask(b2);
            HashSet<String> maskPlayer2 = getMask(b);
            maskPlayer1.retainAll(maskPlayer2);  // Check to see if any pixels in maskPlayer2 are the same as those in maskPlayer1
            if (maskPlayer1.size() > 0) {  // if so, than there exists at least one pixel that is the same in both images, thus
                return maskPlayer1.size();
            }
        }
        return 0;
    }
}

class ComponentMover extends MouseAdapter {

    private Insets dragInsets = new Insets(0, 0, 0, 0);
    private Dimension snapSize = new Dimension(1, 1);
    private Insets edgeInsets = new Insets(0, 0, 0, 0);
    private boolean changeCursor = true;
    private boolean autoLayout = false;
    private Class destinationClass;
    private Component destinationComponent;
    private Component destination;
    private Component source;
    private Point pressed;
    private Point location;
    private Cursor originalCursor;
    private boolean autoscrolls;
    private boolean potentialDrag;

    /**
     * Constructor for moving individual components. The components must be
     * regisetered using the registerComponent() method.
     */
    public ComponentMover() {
    }

    /**
     * Constructor to specify a Class of Component that will be moved when drag
     * events are generated on a registered child component. The events will be
     * passed to the first ancestor of this specified class.
     *
     * @param destinationClass the Class of the ancestor component
     * @param component the Components to be registered for forwarding drag
     * events to the ancestor Component.
     */
    public ComponentMover(Class destinationClass, Component... components) {
        this.destinationClass = destinationClass;
        registerComponent(components);
    }

    /**
     * Constructor to specify a parent component that will be moved when drag
     * events are generated on a registered child component.
     *
     * @param destinationComponent the component drage events should be
     * forwareded to
     * @param components the Components to be registered for forwarding drag
     * events to the parent component to be moved
     */
    public ComponentMover(Component destinationComponent, Component... components) {
        this.destinationComponent = destinationComponent;
        registerComponent(components);
    }

    /**
     * Get the auto layout property
     *
     * @return the auto layout property
     */
    public boolean isAutoLayout() {
        return autoLayout;
    }

    /**
     * Set the auto layout property
     *
     * @param autoLayout when true layout will be invoked on the parent
     * container
     */
    public void setAutoLayout(boolean autoLayout) {
        this.autoLayout = autoLayout;
    }

    /**
     * Get the change cursor property
     *
     * @return the change cursor property
     */
    public boolean isChangeCursor() {
        return changeCursor;
    }

    /**
     * Set the change cursor property
     *
     * @param changeCursor when true the cursor will be changed to the
     * Cursor.MOVE_CURSOR while the mouse is pressed
     */
    public void setChangeCursor(boolean changeCursor) {
        this.changeCursor = changeCursor;
    }

    /**
     * Get the drag insets
     *
     * @return the drag insets
     */
    public Insets getDragInsets() {
        return dragInsets;
    }

    /**
     * Set the drag insets. The insets specify an area where mouseDragged events
     * should be ignored and therefore the component will not be moved. This
     * will prevent these events from being confused with a MouseMotionListener
     * that supports component resizing.
     *
     * @param dragInsets
     */
    public void setDragInsets(Insets dragInsets) {
        this.dragInsets = dragInsets;
    }

    /**
     * Get the bounds insets
     *
     * @return the bounds insets
     */
    public Insets getEdgeInsets() {
        return edgeInsets;
    }

    /**
     * Set the edge insets. The insets specify how close to each edge of the
     * parent component that the child component can be moved. Positive values
     * means the component must be contained within the parent. Negative values
     * means the component can be moved outside the parent.
     *
     * @param edgeInsets
     */
    public void setEdgeInsets(Insets edgeInsets) {
        this.edgeInsets = edgeInsets;
    }

    /**
     * Remove listeners from the specified component
     *
     * @param component the component the listeners are removed from
     */
    public void deregisterComponent(Component... components) {
        for (Component component : components) {
            component.removeMouseListener(this);
        }
    }

    /**
     * Add the required listeners to the specified component
     *
     * @param component the component the listeners are added to
     */
    public void registerComponent(Component... components) {
        for (Component component : components) {
            component.addMouseListener(this);
        }
    }

    /**
     * Get the snap size
     *
     * @return the snap size
     */
    public Dimension getSnapSize() {
        return snapSize;
    }

    /**
     * Set the snap size. Forces the component to be snapped to the closest grid
     * position. Snapping will occur when the mouse is dragged half way.
     */
    public void setSnapSize(Dimension snapSize) {
        if (snapSize.width < 1
                || snapSize.height < 1) {
            throw new IllegalArgumentException("Snap sizes must be greater than 0");
        }

        this.snapSize = snapSize;
    }

    /**
     * Setup the variables used to control the moving of the component:
     *
     * source - the source component of the mouse event destination - the
     * component that will ultimately be moved pressed - the Point where the
     * mouse was pressed in the destination component coordinates.
     */
    @Override
    public void mousePressed(MouseEvent e) {
        source = e.getComponent();
        int width = source.getSize().width - dragInsets.left - dragInsets.right;
        int height = source.getSize().height - dragInsets.top - dragInsets.bottom;
        Rectangle r = new Rectangle(dragInsets.left, dragInsets.top, width, height);

        if (r.contains(e.getPoint())) {
            setupForDragging(e);
        }
    }

    private void setupForDragging(MouseEvent e) {
        source.addMouseMotionListener(this);
        potentialDrag = true;

        //  Determine the component that will ultimately be moved

        if (destinationComponent != null) {
            destination = destinationComponent;
        } else if (destinationClass == null) {
            destination = source;
        } else //  forward events to destination component
        {
            destination = SwingUtilities.getAncestorOfClass(destinationClass, source);
        }

        pressed = e.getLocationOnScreen();
        location = destination.getLocation();

        if (changeCursor) {
            originalCursor = source.getCursor();
            source.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
        }

        //  Making sure autoscrolls is false will allow for smoother dragging of
        //  individual components

        if (destination instanceof JComponent) {
            JComponent jc = (JComponent) destination;
            autoscrolls = jc.getAutoscrolls();
            jc.setAutoscrolls(false);
        }
    }

    /**
     * Move the component to its new location. The dragged Point must be in the
     * destination coordinates.
     */
    @Override
    public void mouseDragged(MouseEvent e) {
        Point dragged = e.getLocationOnScreen();
        int dragX = getDragDistance(dragged.x, pressed.x, snapSize.width);
        int dragY = getDragDistance(dragged.y, pressed.y, snapSize.height);

        int locationX = location.x + dragX;
        int locationY = location.y + dragY;

        //  Mouse dragged events are not generated for every pixel the mouse
        //  is moved. Adjust the location to make sure we are still on a
        //  snap value.

        while (locationX < edgeInsets.left) {
            locationX += snapSize.width;
        }

        while (locationY < edgeInsets.top) {
            locationY += snapSize.height;
        }

        Dimension d = getBoundingSize(destination);

        while (locationX + destination.getSize().width + edgeInsets.right > d.width) {
            locationX -= snapSize.width;
        }

        while (locationY + destination.getSize().height + edgeInsets.bottom > d.height) {
            locationY -= snapSize.height;
        }

        //  Adjustments are finished, move the component

        destination.setLocation(locationX, locationY);
    }

    /*
     *  Determine how far the mouse has moved from where dragging started
     *  (Assume drag direction is down and right for positive drag distance)
     */
    private int getDragDistance(int larger, int smaller, int snapSize) {
        int halfway = snapSize / 2;
        int drag = larger - smaller;
        drag += (drag < 0) ? -halfway : halfway;
        drag = (drag / snapSize) * snapSize;

        return drag;
    }

    /*
     *  Get the bounds of the parent of the dragged component.
     */
    private Dimension getBoundingSize(Component source) {
        if (source instanceof Window) {
            GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
            Rectangle bounds = env.getMaximumWindowBounds();
            return new Dimension(bounds.width, bounds.height);
        } else {
            return source.getParent().getSize();
        }
    }

    /**
     * Restore the original state of the Component
     */
    @Override
    public void mouseReleased(MouseEvent e) {
        super.mouseReleased(e);
        if (!potentialDrag) {
            return;
        }

        source.removeMouseMotionListener(this);
        potentialDrag = false;

        if (changeCursor) {
            source.setCursor(originalCursor);
        }

        if (destination instanceof JComponent) {
            ((JComponent) destination).setAutoscrolls(autoscrolls);
        }

        //  Layout the components on the parent container

        if (autoLayout) {
            if (destination instanceof JComponent) {
                ((JComponent) destination).revalidate();
            } else {
                destination.revalidate();
            }
            destination.repaint();
        }
    }
}
于 2012-12-22T16:39:41.320 回答