TITLE:JInternalFrameをJFrameとして表示する

Posted by at 2009-08-31

JInternalFrameをJFrameとして表示する

`JFrameのタイトルバーなどを非表示にし、JInternalFrame`のタイトルバーでこれらを代用します。

  • &jnlp;
  • &jar;
  • &zip;
InternalFrameTitleBar.png

サンプルコード

final JInternalFrame internal = new JInternalFrame("@title@");
BasicInternalFrameUI ui = (BasicInternalFrameUI)internal.getUI();
Component title = ui.getNorthPane();
for(MouseMotionListener l:title.getListeners(MouseMotionListener.class)) {
  title.removeMouseMotionListener(l);
}
DragWindowListener dwl = new DragWindowListener();
title.addMouseListener(dwl);
title.addMouseMotionListener(dwl);
JPanel p = new JPanel(new BorderLayout());
p.add(new JScrollPane(new JTree()));
p.add(new JButton(new AbstractAction("close") {
  @Override public void actionPerformed(ActionEvent e) {
    Window w = SwingUtilities.windowForComponent((Component)e.getSource());
    //w.dispose();
    w.getToolkit().getSystemEventQueue().postEvent(
      new WindowEvent(w, WindowEvent.WINDOW_CLOSING));
  }
}), BorderLayout.SOUTH);
internal.getContentPane().add(p);
internal.setVisible(true);

KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(new PropertyChangeListener() {
  @Override public void propertyChange(PropertyChangeEvent e) {
    String prop = e.getPropertyName();
    if("activeWindow".equals(prop)) {
      try{
        internal.setSelected(e.getNewValue()!=null);
      }catch(PropertyVetoException ex) {
        ex.printStackTrace();
      }
    }
  }
});
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、`JInternalFrame`のタイトルバーを使用することで、タイトルバーに閉じるボタンのないフレームを作成しています。

  • `JFrame#setUndecorated(true)で、JFrame`のタイトルバーなどを非表示
  • `BasicInternalFrameUI#getNorthPane()JInternalFrame`のタイトルバーを取得
    • 元の`MouseMotionListener`を削除
    • `JInternalFrameをドラッグすると親のJFrameが移動するMouseMotionListener`を追加
  • 制限
    • 最大化、最小化、リサイズなどには未対応
      • `Alt+Space`で最大化、最小化できるが、元のサイズに戻せなくなる場合がある
    • 角の透明化には未対応
      • 目立たなくするために、`LookAndFeelNimbus`に変更
      • `JDK 1.7.0なら、frame.setBackground(new Color(0,0,0,0)); frame.add(p=new MainPanel()); p.setOpaque(false);`で角の透明化が可能

参考リンク

コメント

  • `JFrameのアクティブ状態が変わったら、JInternalFrame`の選択状態も変化するように変更。 -- aterai
  • リサイズ可能?にする場合のテスト -- aterai
//package example;
//-*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
//@homepage@
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;

public class MainPanel extends JPanel{
    public MainPanel() {
        super(new BorderLayout());
        add(makeUI());
        // Translucent resize area for mouse cursor >>>
        setBorder(BorderFactory.createEmptyBorder(4,4,4,4));
        setBackground(new Color(0,0,1,0.01f));
        //<<<
        setPreferredSize(new Dimension(320, 240));
    }
    public JComponent makeUI() {
        final JInternalFrame internal = new JInternalFrame("@title@");
        BasicInternalFrameUI ui = (BasicInternalFrameUI)internal.getUI();
        Component title = ui.getNorthPane();
        for (MouseMotionListener l:title.getListeners(MouseMotionListener.class)) {
            title.removeMouseMotionListener(l);
        }
        DragWindowListener dwl = new DragWindowListener();
        title.addMouseListener(dwl);
        title.addMouseMotionListener(dwl);
        JPanel p = new JPanel(new BorderLayout());
        p.add(new JScrollPane(new JTree()));
        p.add(new JButton(new AbstractAction("close") {
            @Override public void actionPerformed(ActionEvent e) {
                Window w = SwingUtilities.windowForComponent((Component)e.getSource());
                //w.dispose();
                w.dispatchEvent(new WindowEvent(w, WindowEvent.WINDOW_CLOSING));
            }
        }), BorderLayout.SOUTH);
        internal.getContentPane().add(p);
        internal.setVisible(true);

        KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        focusManager.addPropertyChangeListener(new PropertyChangeListener() {
            @Override public void propertyChange(PropertyChangeEvent e) {
                String prop = e.getPropertyName();
                //System.out.println(prop);
                if ("activeWindow".equals(prop)) {
                    try {
                        internal.setSelected(e.getNewValue()!=null);
                    } catch (PropertyVetoException ex) {
                        ex.printStackTrace();
                    }
                    //System.out.println("---------------------");
                }
            }
        });
        return internal;
    }
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                createAndShowGUI();
            }
        });
    }
    public static void createAndShowGUI() {
        JFrame frame = new JFrame();
        try {
            //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            for(UIManager.LookAndFeelInfo laf:UIManager.getInstalledLookAndFeels()) {
                if("Nimbus".equals(laf.getName())) {
                    UIManager.setLookAndFeel(laf.getClassName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        frame.setUndecorated(true);
        JRootPane root = frame.getRootPane();
        root.setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
        JLayeredPane layeredPane = root.getLayeredPane();
        Component c = layeredPane.getComponent(1);
        if (c instanceof JComponent) {
            JComponent orgTitlePane = (JComponent)c;
            orgTitlePane.setVisible(false);
            //layeredPane.remove(orgTitlePane);
        }
        //JComponent dummyTitlePane = new JLabel();
        //layeredPane.add(dummyTitlePane, JLayeredPane.FRAME_CONTENT_LAYER);
        //dummyTitlePane.setVisible(true);

        frame.setMinimumSize(new Dimension(300, 120));
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.getContentPane().add(new MainPanel());
        frame.setBackground(new Color(0,0,0,0)); //JDK 1.7
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
class DragWindowListener extends MouseAdapter {
    private MouseEvent start;
    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());
            }
        }
        start = me;
    }
    @Override public void mouseDragged(MouseEvent me) {
        if (window!=null) {
            Point pt = new Point(); pt = window.getLocation(pt);
            int x = pt.x - start.getX() + me.getX();
            int y = pt.y - start.getY() + me.getY();
            window.setLocation(x, y);
        }
    }
}