概要

JWindowなどのタイトルバーのないフレームをマウスで移動します。

サンプルコード

public void createSplashScreen(String path) {
  ImageIcon img = new ImageIcon(getClass().getResource(path));
  DragWindowListener dwl = new DragWindowListener();
  splashLabel = new JLabel(img);
  splashLabel.addMouseListener(dwl);
  splashLabel.addMouseMotionListener(dwl);
  splashScreen = new JWindow(getFrame());
  splashScreen.getContentPane().add(splashLabel);
  splashScreen.pack();
  splashScreen.setLocationRelativeTo(null);
}
class DragWindowListener extends MouseAdapter {
  private final Point startPt = new Point();
  //private Point  loc;
  private Window window;
  @Override public void mousePressed(MouseEvent me) {
    startPt.setLocation(me.getPoint());
  }
  @Override public void mouseDragged(MouseEvent me) {
    if (window == null) {
      window = SwingUtilities.windowForComponent(me.getComponent());
    }
    Point eventLocationOnScreen = me.getLocationOnScreen();
    window.setLocation(eventLocationOnScreen.x - startPt.x,
                       eventLocationOnScreen.y - startPt.y);
    //loc = window.getLocation(loc);
    //int x = loc.x - start.getX() + me.getX();
    //int y = loc.y - start.getY() + me.getY();
    //window.setLocation(x, y);
  }
}
view all

解説

JWindowや、setUndecorated(true)したJFrameのようにタイトルバーのないフレームをマウスのドラッグで移動します。実際はJWindowに、MouseMotionListenerなどを実装したコンポーネントを追加しています。

上記のサンプルでは、Splash ScreenJLabelにリスナーを追加し、これをJWindowに貼り付けてドラッグできるようにしています。

次に開くsetUndecorated(true)したJFrameでは、青いラベル部分をドラッグすることが出来ます。


  • マルチディスプレイなどで、別画面に移動できないバグ?を修正
    • ただし、Web StartSandBox内では、以前と同じく画面の外に移動することができない?
      • JNLPのセキュリティにall-permissionsを設定する必要がある
  • Swing TutorialFrameDemo2で試しても、同様?
    • Look and feel decorated: 画面外に移動不可
    • Window system decorated: 画面外に移動可能

参考リンク

コメント

  • JLabel無しでJFrameを直接つかんで移動させようと,ソース中のDragWindowListenerFrameの引数に指定してaddMouseListener()addMouseMotionListener()に追加してみたのですが,うまく動きませんでした。ラベルではなくフレームを直接つかんで移動させるにはどうすればよいのでしょうか? -- hshs
    • frame.getContentPane().addMouseListener(dwl);...と、ContentPaneRootPaneDragWindowListenerを追加するか、以下のようにDragWindowListenerを変更するのはどうでしょうか? -- aterai
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MainPanel {
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    DragWindowListener dwl = new DragWindowListener();
    JFrame frame = new JFrame();
    frame.setUndecorated(true);
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.addMouseListener(dwl);
    frame.addMouseMotionListener(dwl);
    frame.setSize(320, 240);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}
class DragWindowListener extends MouseAdapter {
  private final Point startPt = new Point();
  private Window window;
  @Override public void mousePressed(MouseEvent me) {
    if (window == null) {
      Object o = me.getSource();
      if (o instanceof Window) {
        window = (Window) o;
      } else if (o instanceof JComponent) {
        window = SwingUtilities.windowForComponent(me.getComponent());
      }
    }
    startPt.setLocation(me.getPoint());
  }
  @Override public void mouseDragged(MouseEvent me) {
    if (window != null) {
      Point eventLocationOnScreen = me.getLocationOnScreen();
      window.setLocation(eventLocationOnScreen.x - startPt.x,
                         eventLocationOnScreen.y - startPt.y);
    }
  }
}
  • えーと、このソースは新たにJPanelを継承してるんですね、という事は結局、JFrame自体をマウスドラッグでつかむことが出来ないということなんでしょうか? -- hshs
    • JFrameContentPaneJPanelを継承したダミーコンポーネントをサンプルとして追加してるだけです。必要ないなら上記のように削除して(どこを削除したかはこのページ上にある「編集された箇所をみる」などで調べてください)調査してみるのがお手軽なのでオススメです。JFrameに追加したリスナーでJFrameの移動を行うことは可能ですが、本当に「JFrame自体をマウスドラッグでつかむことが出来ない」かどうかについては、内部での処理を追っていないのでよく分かりません。 -- aterai
  • 返信ありがとうございます,最初のサンプル中のcreateAndShowGUI()内や,showFrame()や,start(JFrame frame)内などに,DragWindowListener dwl = new DragWindowListener();frame.addMouseListener(dwl);frame.addMouseMotionListener(dwl);を入れて見たりしたのですが動作しないのですが,これは何故なんでしょうか?、何か必要な命令が足りないのでしょうか。 -- hshs
    • 失礼、見落としてました。自分の環境(JDK 1.7.0_17, Windows 7)では、特に問題なく動作(Exceptionなども出ていない)しています。環境と変更したソース自体をどこか(例えば https://gist.github.com/ とか)に投稿できますか? -- aterai
  • あっ、動作しないというのは「JFrame自体をマウスドラッグでつかむことが出来ない」という意味で,通常の動作は問題ないです,上記のように追加変更して見たら,ラベルの部分だけでなく真ん中のフレーム部分を,マウスでドラッグしてつかんで移動させられるのかなと思ったのですが,実際つかんで移動させようとすると,Exception in thread "AWT-EventQueue-0" java.lang.NullPointerExceptionが出てきてつかめなかったので....。GitHubのアカウントは持ってないですw,環境はJDK1.7.0_15,win7,64bit,ソースは上の三行を追加してみただけです。 --
    • 「上の三行を追加してみただけ」だとDragWindowListenerが新しくなっていない(コメントのDragWindowListenerになっていない)ので、NullPointerExceptionが発生していると考えて良さそうです(ソースコードの行とかが分からないので推測ですが)。src.zipやリポジトリのDragWindowListenerも更新した(ついでに上記のコメントのDragWindowListenerもアップデート)ので、最新版で試してみてください。 -- aterai
    • 余談: gistってアカウント必要でしたっけ? -- aterai
  • gistってアカウント無しで投稿出来るんですね,知りませんでしたm(__)m,再UPしていただいたsrc.zipで上記の動作を確認できました。ありがとうございます。DragWindowListener内部の追加されていたコードの意味が自分にはまだ理解できませんが,もっと勉強したいと思います。 -- hshs