【问题标题】:Drag component within a JPanel using Gridbag layout manager使用 Gridbag 布局管理器在 JPanel 中拖动组件
【发布时间】:2016-03-06 18:06:41
【问题描述】:

我正在尝试在 JPanel 中实现 J 组件的拖动。 JPanel 必须使用 Gridbag 布局管理器。 我查看了很多拖拽代码,包括Moving Windows。他们都使用component.setLocation(x, y);,这在使用 Gridbag 布局管理器时无效。 我需要其他方法的帮助。

【问题讨论】:

  • 您需要动态更改 Gridbag 的权重以响应鼠标拖动。
  • GridBagLayout 使用约束来控制显示组件的单元格。您不能只是将一个组件拖到另一个单元格中,因为该单元格中已经存在一个组件。拖动是为了与空布局一起使用,这就是您看到的其他代码使用 setLocation(...) 方法的原因。
  • 您需要进行一些认真的计算以确定在您想要的位置添加组件所需的布局约束,以及可能更改其周围组件的约束,以生成位移

标签: java swing drag gridbaglayout


【解决方案1】:

如果 JComponent 是 JPanel 中唯一的组件,那么任务并没有那么复杂。这是一个小的演示程序(具有重新调整组件大小以响应鼠标滚轮事件的奖励):

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);
            }
        });
    }
}

如果 JPanel 包含多个组件,它就变成了一个完全不同的球类游戏。使用多个组件时,功能类似于您使用 Eclipse 的 IDE Windowbuilder 等 GUI 构建器获得的功能,您可以在其中交互式地移动组件。

【讨论】:

  • 感谢所有回复和回答。我现在对所涉及的内容有了更清晰的了解,并且如果没有其他组件存在,则可以使用 Gridbag 布局在面板内拖动一个很好的简单解决方案。
猜你喜欢
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 2022-06-29
  • 1970-01-01
  • 1970-01-01
  • 2020-06-27
  • 2012-09-29
  • 1970-01-01
相关资源
最近更新 更多