• category: swing folder: CustomDecoratedFrame title: JFrameのタイトルバーなどの装飾を独自のものにカスタマイズする tags: [JFrame, MouseListener, MouseMotionListener, JPanel, JLabel, ContentPane, Transparent] author: aterai pubdate: 2010-01-18T11:27:29+09:00 description: JFrameのタイトルバーなどを非表示にして独自に描画し、これに移動リサイズなどの機能も追加します。 image: https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTKV1P7mYI/AAAAAAAAAV0/u4qjd-ItBYU/s800/CustomDecoratedFrame.png hreflang:
       href: http://java-swing-tips.blogspot.com/2010/05/custom-decorated-titlebar-jframe.html
       lang: en

概要

JFrameのタイトルバーなどを非表示にして独自に描画し、これに移動リサイズなどの機能も追加します。

サンプルコード

class ResizeWindowListener extends MouseAdapter {
  private Rectangle startSide = null;
  private final JFrame frame;
  public ResizeWindowListener(JFrame frame) {
    this.frame = frame;
  }
  @Override public void mousePressed(MouseEvent e) {
    startSide = frame.getBounds();
  }
  @Override public void mouseDragged(MouseEvent e) {
    if (startSide == null) return;
    Component c = e.getComponent();
    if (c == topleft) {
      startSide.y += e.getY();
      startSide.height -= e.getY();
      startSide.x += e.getX();
      startSide.width -= e.getX();
    } else if (c == top) {
      startSide.y += e.getY();
      startSide.height -= e.getY();
    } else if (c == topright) {
      startSide.y += e.getY();
      startSide.height -= e.getY();
      startSide.width += e.getX();
    } else if (c == left) {
      startSide.x += e.getX();
      startSide.width -= e.getX();
    } else if (c == right) {
      startSide.width += e.getX();
    } else if (c == bottomleft) {
      startSide.height += e.getY();
      startSide.x += e.getX();
      startSide.width -= e.getX();
    } else if (c == bottom) {
      startSide.height += e.getY();
    } else if (c == bottomright) {
      startSide.height += e.getY();
      startSide.width += e.getX();
    }
    frame.setBounds(startSide);
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルではタイトルバーを、setUndecorated(true)で非表示にし、移動可能にしたJPanelを追加してタイトルバーにしています。 リサイズは、Swing - Undecorated and resizable dialogBasicInternalFrameUI.javaMetalRootPaneUI#MouseInputHandlerなどを参考にして、周辺にそれぞれ対応するリサイズカーソルを設定したJLabelを配置しています。


JDK 1.7.0の場合、JFrameの背景色を透明(frame.setBackground(new Color(0x0, true));)にし、ContentPaneの左右上の角をクリアして透明にしています。


JRootPaneにリサイズのための装飾を設定するのように、JRootPane#setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);を使用してリサイズする方法もあります。

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

public class WindowDecorationStyleTest {
  public JComponent makeTitleBar() {
    JLabel label = new JLabel("Title");
    label.setOpaque(true);
    label.setForeground(Color.WHITE);
    label.setBackground(Color.BLACK);
    DragWindowListener dwl = new DragWindowListener();
    label.addMouseListener(dwl);
    label.addMouseMotionListener(dwl);

    JPanel title = new JPanel(new BorderLayout());
    title.setBorder(BorderFactory.createMatteBorder(0, 4, 4, 4, Color.BLACK));
    title.add(label);
    title.add(new JButton(new AbstractAction("x") {
      @Override public void actionPerformed(ActionEvent e) {
        Window w = SwingUtilities.windowForComponent((Component) e.getSource());
        w.dispatchEvent(new WindowEvent(w, WindowEvent.WINDOW_CLOSING));
      }
    }), BorderLayout.EAST);
    return title;
  }
  public JComponent makeUI() {
    return new JScrollPane(new JTree());
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame frame = new JFrame();
    frame.setUndecorated(true);

    WindowDecorationStyleTest demo = new WindowDecorationStyleTest();
    JRootPane root = frame.getRootPane();
    root.setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
    root.setBorder(BorderFactory.createMatteBorder(4, 8, 8, 8, Color.BLACK));
    JLayeredPane layeredPane = root.getLayeredPane();
    Component c = layeredPane.getComponent(1);
    if (c instanceof JComponent) {
      JComponent orgTitlePane = (JComponent) c;
      orgTitlePane.removeAll();
      orgTitlePane.setLayout(new BorderLayout());
      orgTitlePane.add(demo.makeTitleBar());
    }
    frame.setMinimumSize(new Dimension(300, 120));
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(demo.makeUI());
    frame.setSize(320, 240);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}

class DragWindowListener extends MouseAdapter {
  private final transient 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 pt = new Point();
      pt = window.getLocation(pt);
      int x = pt.x - startPt.x + me.getX();
      int y = pt.y - startPt.y + me.getY();
      window.setLocation(x, y);
    }
  }
}

参考リンク

コメント