Swing:创建可拖动组件...?

27

我在网上搜索了可拖动的Swing组件的示例,但是我找到的示例要么不完整,要么无法正常工作。

我需要一个Swing组件,可以通过鼠标在另一个组件内拖动。在被拖动时,它应该即时改变位置,而不仅仅是“跳”到目的地。

我希望有没有使用非标准API的示例。

谢谢。

2个回答

45

我提出了一个简单但有效的解决方案,是我自己发现的 ;)

我该怎么做?

  • 当鼠标被按下时,我记录鼠标在屏幕上的位置和组件的位置。
  • 当鼠标被拖动时,我计算新旧鼠标在屏幕上的位置之间的差异,并将组件移动这个差值的距离。

在最新的JDK 6下在Linux(OpenSuse,KDE3)进行了测试,但嘿,这是Java Swing,应该在任何地方都能正常工作。

以下是代码:

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

public class MyDraggableComponent
    extends JComponent {

  private volatile int screenX = 0;
  private volatile int screenY = 0;
  private volatile int myX = 0;
  private volatile int myY = 0;

  public MyDraggableComponent() {
    setBorder(new LineBorder(Color.BLUE, 3));
    setBackground(Color.WHITE);
    setBounds(0, 0, 100, 100);
    setOpaque(false);

    addMouseListener(new MouseListener() {

      @Override
      public void mouseClicked(MouseEvent e) { }

      @Override
      public void mousePressed(MouseEvent e) {
        screenX = e.getXOnScreen();
        screenY = e.getYOnScreen();

        myX = getX();
        myY = getY();
      }

      @Override
      public void mouseReleased(MouseEvent e) { }

      @Override
      public void mouseEntered(MouseEvent e) { }

      @Override
      public void mouseExited(MouseEvent e) { }

    });
    addMouseMotionListener(new MouseMotionListener() {

      @Override
      public void mouseDragged(MouseEvent e) {
        int deltaX = e.getXOnScreen() - screenX;
        int deltaY = e.getYOnScreen() - screenY;

        setLocation(myX + deltaX, myY + deltaY);
      }

      @Override
      public void mouseMoved(MouseEvent e) { }

    });
  }

}

public class Main {

  public static void main(String[] args) {
    JFrame f = new JFrame("Swing Hello World");

    // by doing this, we prevent Swing from resizing
    // our nice component
    f.setLayout(null);

    MyDraggableComponent mc = new MyDraggableComponent();
    f.add(mc);

    f.setSize(500, 500);

    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    f.setVisible(true);
  }

}

1
如果您使用 MouseAdapterMouseMotionAdapter 代替监听器,则不需要覆盖这些额外方法。 - Vessel

2
此外,我发现可以在JFrame内创建JInternalFrame,但问题是:你总会得到一个让人烦恼的窗口标题栏。
要禁用标题栏,不幸的是需要采取一种肮脏的解决方法:
public class MyDraggableComponent extends JInternalFrame {

  public MyDraggableComponent() {
    InternalFrameUI thisUI = getUI();
    if (thisUI instanceof BasicInternalFrameUI) {
      ((BasicInternalFrameUI) thisUI).setNorthPane(null);
    }

}

我真的很想有一个像“someInternalFrame.setWindowTitleBar(false)”这样的方法... :'(

3
子类化可以提供setWindowTitleBar()方法! - 11684

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