TITLE:JInternalFrameをModalにする
#navi(../)
*JInternalFrameをModalにする [#le7c13f6]
>編集者:[[Terai Atsuhiro>terai]]~
作成日:2007-10-15~
更新日:&lastmod;

#contents

**概要 [#uc990f8e]
JInternalFrameをModalにして、他のJInternalFrameなどを操作できないようにブロックします。

#screenshot

**サンプルコード [#d9d01b15]
#code{{
class OpenNomalDialogAction extends AbstractAction {
  public OpenNomalDialogAction(String label) {
    super(label);
  }
  public void actionPerformed(ActionEvent e) {
    setJMenuEnabled(false);
    JOptionPane.showInternalMessageDialog(
      desktop, "information", "title", JOptionPane.INFORMATION_MESSAGE);
    setJMenuEnabled(true);
  }
}

class OpenDialogAction extends AbstractAction {
  private final MyGlassPane glass = new MyGlassPane();
  public OpenDialogAction(String label) {
    super(label);
    Rectangle screen = frame.getGraphicsConfiguration().getBounds();
    glass.setBorder(BorderFactory.createEmptyBorder());
    glass.setLocation(0,0);
    glass.setSize(screen.width, screen.height);
    glass.setOpaque(false);
    glass.setVisible(false);
    desktop.add(glass, JLayeredPane.MODAL_LAYER);
  }
  public void actionPerformed(ActionEvent e) {
    setJMenuEnabled(false);
    glass.setVisible(true);
    JOptionPane.showInternalMessageDialog(
      desktop, "information", "title", JOptionPane.INFORMATION_MESSAGE);
    glass.setVisible(false);
    setJMenuEnabled(true);
  }
}

class OpenAction extends AbstractAction {
  private final Component orgGlassPane;
  private final JPanel glass = new MyGlassPane();
  public OpenAction(String label) {
    super(label);
    orgGlassPane = frame.getGlassPane();
    glass.setVisible(false);
  }
  public void actionPerformed(ActionEvent e) {
    setJMenuEnabled(false);
    JOptionPane optionPane = new JOptionPane();
    optionPane.setMessage("Hello, World");
    optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
    JInternalFrame modal = optionPane.createInternalFrame(desktop, "title");
    removeSystemMenuListener(modal);
    modal.addInternalFrameListener(new InternalFrameAdapter() {
      public void internalFrameClosed(InternalFrameEvent e) {
        glass.setVisible(false);
        frame.setGlassPane(orgGlassPane);
        setJMenuEnabled(true);
      }
    });
    glass.add(modal);
    Rectangle screen = desktop.getBounds();
    modal.setLocation(screen.x + screen.width/2  - modal.getSize().width/2,
              screen.y + screen.height/2 - modal.getSize().height/2);
    frame.setGlassPane(glass);
    glass.setVisible(true);
    modal.setVisible(true);
    try{
      modal.setSelected(true);
    }catch(java.beans.PropertyVetoException ex) {}
  }
}
}}
-&jnlp;
-&jar;
-&zip;

**解説 [#v497998b]
-Alt+U: JOptionPane.showInternalMessageDialogメソッドを使用して、簡単なメッセージを表示するModalなDialogをJDeskTopPane内に表示します。
-- Mnemonicがうまく無効に出来ないため、Alt+Bでボタンを押すことが出来てしまいます(Mnemonicを設定したコンポーネントはsetEnabled(false)とする必要がある)。
-- MnemonicをJMenuに設定しているとsetEnabled(false)としても、Altキーに反応してしまう(WindowsLnFだけ?)ので、ダイアログを表示している間は、JMenuBarをダミーと入れ替えています。
-- このダイアログを閉じない限り、アプリケーションをAlt+F4などで閉じることは出来ません。
-- ダイアログのシステムメニュー(左上のアイコンをクリックすると表示される)がマウスで操作できません。

-Alt+I: Alt+Uと同様ですが、%%もう一枚タイトルバーなどを削除した半透明なJInternalFrameを下の%% 半透明なGlassPaneをJLayeredPane.MODAL_LAYERに追加して表示しています。
-- JDeskTop内にマスクが掛かります。

-Alt+M: JFrameに半透明なGlassPaneを追加し、そこにJInternalFrameを追加することでModalにしています。
-- JFrame内全体(JMenuBarなども含む)にマスクが掛かります。
-- %%ダイアログのシステムメニューが自身のレイヤより奥に表示されるため、アイコン(JLabel)をクリックしても反応しないようにリスナーを取り除いています。%%
-- このダイアログを開いていても、アプリケーションをAlt+F4などで閉じることが出来てしまいます。

----
[[Alexander Potochkin's Blog: Disabling Swing Containers, the final solution?>http://weblogs.java.net/blog/alexfromsun/archive/2008/01/disabling_swing.html]]を参考に((paint ではなく、print を使うのがポイント。これは便利、他にも色々使えそう。))して、GlassPane を以下のように修正すると、上記のサンプルのAlt+M((Alt+Iの場合は、描画が乱れる))は、Mnemonic もうまくブロックできるようです。
-JFrameのメニューバーのMnemonicもブロックできる
-JFrameのシステムメニューはブロックできない
-モーダルにしたJInternalFrameのシステムメニューは表示されない
--ただし表示されないだけで、クリックしてからカーソル移動やダブルクリックなどが動いてしまう
-モーダルにしたJInternalFrameの右上の閉じるボタンのJToolTip が、JFrame内では空白になる

#code{{
class MyGlassPane2 extends JPanel {
  private final MouseInputAdapter adapter = new MouseInputAdapter() {};
  private final TexturePaint texture;
  public MyGlassPane2() {
    super((LayoutManager)null);
    setOpaque(false);
    addMouseListener(adapter);
    addMouseMotionListener(adapter);
    setFocusTraversalPolicy(new DefaultFocusTraversalPolicy() {
      public boolean accept(Component c) {return false;}
    });
    texture = new TexturePaint(checkeredImage, new Rectangle2D.Double(0,0,16,16));
  }
  @Override
  public void setVisible(boolean isVisible) {
    boolean oldVisible = isVisible();
    super.setVisible(isVisible);
    JRootPane rootPane = SwingUtilities.getRootPane(this);
    if(rootPane!=null && isVisible()!=oldVisible) {
      rootPane.getLayeredPane().setVisible(!isVisible);
    }
  }
  @Override
  public void paintComponent(Graphics g) {
    JRootPane rootPane = SwingUtilities.getRootPane(this);
    if(rootPane!=null) {
      //http://weblogs.java.net/blog/alexfromsun/archive/2008/01/disabling_swing.html
      // it is important to call print() instead of paint() here
      // because print() doesn't affect the frame's double buffer
      rootPane.getLayeredPane().print(g);
    }
    Graphics2D g2 = (Graphics2D) g;
    g2.setPaint(texture);
    g2.fillRect(0,0,getWidth(),getHeight());
  }
}
}}

**参考リンク [#n6c5a455]
-[[Creating Modal Internal Frames -- Approach 1 and Approach 2>http://java.sun.com/developer/JDCTechTips/2001/tt1220.html]]
-[[How to Use Root Panes>http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html]]

**コメント [#h8218ae6]
- %%[[JInternalFrameを半透明にする>Swing/TransparentFrame]]と、同様にGlassPaneがUbuntu(GNOME)などで半透明にならない場合があります。%% -- [[terai]] &new{2007-10-15 (月) 13:16:07};
-- (Alt+I)で開いた場合、JInternalFrameにGlassPaneを乗せるのではなく、直接JDeskTopPaneのJLayeredPane.MODAL_LAYERに追加するように変更しました。 -- [[terai]] &new{2007-10-16 (火) 17:31:50};
- メモ: [[Alexander Potochkin's Blog: Disabling Swing Containers, the final solution?>http://weblogs.java.net/blog/alexfromsun/archive/2008/01/disabling_swing.html]]のサンプルでは、Mnemonic もちゃんとブロックできているようなので、「あとで調べる & 参考にする」こと。 -- [[terai]] &new{2008-01-25 (金) 17:28:21};

#comment