Drag component within a JPanel using Gridbag layout manager

主宰稳场 提交于 2020-07-09 05:42:05

问题


I am trying to implement dragging of a J component within a JPanel. The JPanel has to use Gridbag layout manager. I reviewed many dragging codes, including Moving Windows. They all use component.setLocation(x, y); which has no effect when using Gridbag layout manager. I need help with alternative approach.


回答1:


if the JComponent is the only component in the JPanel, the task is not that complicated. Here is a small demo program that does it (with a bonus of re-sizing the component in response to mouse wheel events) :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;

public class GridbagDragDemo extends JPanel {

    /**
     * Pixel width and height of positioned component.
     */
    private float  width, height;

    /**
     * Layout manger for this.
     */
    private GridBagLayout gbl;

    /**
     * Layout horizontal weights for left and right gap, and component.
     */
    private float leftWeight,xCompWeight, rightWeight;

    /**
     * Layout vertical weights for top and right gap, and component.
     */
    private float topWeight,yCompWeight, bottomWeight;

    /**
     * Min and max weight values.
     * These values can be changed to change the sensitivity of dragging.
     * For better responsiveness W_MAX can be changed in respect to the JPanl's size.
     * (also a different W_MAX can be set to horizontal and vertical axis.
     */
    private float W_MIN = 0, W_MAX = 2;

    /**
     * Keep sum an even number for calculating (int) W_SUM/2
     */
    private float W_SUM = W_MIN + W_MAX;

    /**
     * Represents the change in ratio between left / right weights
     * and top/bottom weights for every pixel of mouse drag.
     * The higher the factor the faster / more sensitive the
     * component move is.
     * Try different values to get the responsiveness you need.
     */
    private float WEIGHT_DELTA = 0.01f;

    /**
     * Represents the change (in pixels) in component width and height
     * and top/bottom weights for every mouse wheel notch.
     * The higher the factor the faster / more sensitive the
     * component resize.
     * Try different values to get the responsiveness you need.
     */
    private static final int ZOOM_FACTOR = 4;

    /**
     * Store mouse pressed position.
     */
    private float pX, pY;

    /**
     * The dragged component
     */
    private JComponent component;

    public GridbagDragDemo() {

        //set initial position to center
        leftWeight = W_SUM/2 ; xCompWeight = 0;  rightWeight = W_SUM/2;
        topWeight = W_SUM/2 ; yCompWeight = 0;  bottomWeight = W_SUM/2;

        setPreferredSize(new Dimension(400, 300));

        gbl = new GridBagLayout();
        gbl.columnWidths = new int[] {0, 0, 0};
        gbl.rowHeights = new int[] {0, 0, 0};
        gbl.columnWeights = new double[]{leftWeight , xCompWeight, rightWeight };
        gbl.rowWeights = new double[]{topWeight,yCompWeight, bottomWeight};
        setLayout(gbl);
        setBackground(Color.YELLOW);

        component = new JPanel();
        component.setPreferredSize(new Dimension(75,75));
        component.setMinimumSize(new Dimension(15,15));
        component.setMaximumSize(new Dimension(225,225));
        component.setBackground(Color.ORANGE);
        component.setBorder(new LineBorder(Color.black, 3));

        //add drag listeners
        component.addMouseMotionListener(new MouseMotionAdapter(){
            @Override
            public void mouseDragged(MouseEvent me) {

                int mouseX = me.getXOnScreen();
                int mouseY = me.getYOnScreen();

                float moveX  =  mouseX - pX;
                float moveY  =  mouseY - pY;

                pX = mouseX;
                pY = mouseY;

                moveComp(moveX , moveY);

            }
        });
        component.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent me) {

                //store pressed position
                pX = me.getXOnScreen();
                pY = me.getYOnScreen();
            }
        });

        //add resize listener
        component.addMouseWheelListener(new MouseWheelListener() {

            @Override
            public void mouseWheelMoved(MouseWheelEvent me) {

                //change sign so rolling "up" will be positive
                reSizeComp(- me.getWheelRotation());
            }
        });

        GridBagConstraints gbc_panel = new GridBagConstraints();
        gbc_panel.fill = GridBagConstraints.BOTH;
        gbc_panel.gridx = 1;
        gbc_panel.gridy = 1;
        add(component, gbc_panel);

        width  = component.getPreferredSize().width;
        height = component.getPreferredSize().height;
    }

    private void moveComp(float moveX, float moveY) {

        if(Math.abs(moveX)>0) {

            leftWeight += WEIGHT_DELTA * moveX;
            leftWeight = (float) setValueInRange(leftWeight,  W_MIN, W_MAX);
            rightWeight = W_SUM - leftWeight;
        }

        if(Math.abs(moveY)>0) {

            topWeight += WEIGHT_DELTA * moveY;
            topWeight = (float) setValueInRange(topWeight, W_MIN, W_MAX );
            bottomWeight = W_SUM - topWeight;
        }

        gbl.columnWeights = new double[]{leftWeight,xCompWeight, rightWeight};
        gbl.rowWeights    = new double[]{topWeight, yCompWeight, bottomWeight};

        refresh();
    }

    /**
     *
     */
    private void refresh() {

        revalidate();
        getParent().repaint();
    }

    private void reSizeComp(int notches) {

        width += notches*ZOOM_FACTOR  ; height += notches *ZOOM_FACTOR  ;

        //respect min / max component size
        width  = (float) setValueInRange(width, component.getMinimumSize().getWidth(),
                                                    component.getMaximumSize().getWidth() );
        height = (float) setValueInRange(height, component.getMinimumSize().getHeight(),
                                                    component.getMaximumSize().getHeight() );
        component.setPreferredSize(new Dimension((int)width,(int)height));

        refresh();
    }

    private double setValueInRange(double value, double min, double max) {

        value = (value < min ) ? min : value;
        value = (value > max ) ? max : value;

        return value;
    }

    public static void main(String args[]) {

        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                JFrame frame = new JFrame("Test Gridbag drag");  
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                frame.setPreferredSize(new Dimension(400, 300));
                frame.add(new GridbagDragDemo());
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

If the JPanel holds multiple components, it becomes a totally different ball game. With multiple components the functionality is similar to what you get using GUI builders like Eclipse' IDE Windowbuilder, where you can interactively move components.



来源:https://stackoverflow.com/questions/35830499/drag-component-within-a-jpanel-using-gridbag-layout-manager

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!