在JFrame中拖动JPanel

3
我在点击按钮时将JPanel添加到JFrame中。它会将JPanel添加到框架中。每次单击事件时,该按钮都会继续向JFrame添加JPanel,没有任何限制。当单击按钮时,我还将JPanels添加到List中。我这样做是因为使用for循环添加MouseMotionListener来处理JPanel的拖动。
现在我面临的问题是拖动。当我通过单击添加第一个JPanel并拖动它时,它会正确地跟随鼠标光标坐标。当我添加第二个JPanel时,它也完美地跟随鼠标。但是,在添加第二个JPanel之后,如果尝试拖动第一个JPanel,则第一个JPanel似乎会跟随不同的坐标移动,初始位置将更改为其他位置。我不知道我犯了什么错误。请帮助我解决这个问题。请查看下面的代码。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class MyFrame extends JFrame {

    JButton jb;
    List<JPanel> mypanels = new ArrayList<JPanel>();
    public MyFrame() {
        jb = new JButton("Add Panel");
        jb.setBounds(10, 10, 100, 50);
        setSize(new Dimension(1000, 600));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(null);
        add(jb);
        setVisible(true);
        initialize();
    }


    public void initialize() {

        jb.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                JPanel panel = new JPanel();
                panel.setBounds(150,150,200,200);
                panel.setBackground(Color.black);
                mypanels.add(panel);
                add(panel);
                repaint();
                handleDrag();
            }
        });

    }

    public void handleDrag(){
        for(int i=0;i<mypanels.size();i++) {
            final int j = i;
            mypanels.get(i).addMouseMotionListener(new MouseMotionAdapter() {

                @Override
                public void mouseDragged(MouseEvent me) {
                    me.translatePoint(me.getComponent().getLocation().x, me.getComponent().getLocation().y);
                    mypanels.get(j).setLocation(me.getX(), me.getY());
                }

            });
        }
    }

    public static void main(String args[]) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                new MyFrame();
            }
        });

    }


}

1
你是否在GUI数据模型中存储了JPanels的边界? - Gilbert Le Blanc
不,我没有存储任何 JPanels 的边界。 - Vinay
那么,它们被拖动后你怎么知道它们在哪里? - Gilbert Le Blanc
1
我不知道你这样做的实现细节,但是你考虑过使用类似 JInternalFrame 的东西吗?(同时也可以参考其 Java 教程)。只是确保你没有不必要地重新发明轮子 :) - Brian
@Gilbert,我在translate()中使用了me.getComponent().getLocation().x。我以为它给出了发生单击事件的特定JPanel的位置。 - Vinay
@Brian 我已经尝试使用JInternalFrame,但由于某些原因它不符合我的要求。 - Vinay
3个回答

7

看起来你的handleDrag方法在向列表中添加一个JPanel时,会为每个JPanel添加一个新的匿名监听器。只需要添加一次监听器即可,如果添加了多个监听器,则行为会变得奇怪。

这是更新后的handleDrag方法:

    public void handleDrag(JPanel panel){
    final JPanel p = panel;
        panel.addMouseMotionListener(new MouseMotionAdapter() {

            @Override
            public void mouseDragged(MouseEvent me) {
                me.translatePoint(me.getComponent().getLocation().x, me.getComponent().getLocation().y);
                p.setLocation(me.getX(), me.getY());
            }

        });
}

2
+1,但是你应该声明方法参数本身为final,而不仅仅是在方法体中使用类似的对象。 - FThompson

5

Joe是正确的,这是我在我的项目中所完成的handleDrag方法:

public void handleDrag(final JPanel panel){
    panel.addMouseListener(new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent me) {
             x = me.getX();
             y = me.getY();
        }
    });
    panel.addMouseMotionListener(new MouseMotionAdapter() {
        @Override
        public void mouseDragged(MouseEvent me) {
            me.translatePoint(me.getComponent().getLocation().x-x, me.getComponent().getLocation().y-y);
            panel.setLocation(me.getX(), me.getY());
        }
    });
}

这样点击面板时就不会出现初始的“跳跃”现象。

2
  • 可以看一下@camickr的移动窗口

  • 不要同时使用ComponentMoverComponentResizer


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接