Swing/ModalInternalFrame のバックアップ(No.20)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/ModalInternalFrame へ行く。
- 1 (2008-01-25 (金) 23:38:26)
- 2 (2008-01-29 (火) 21:34:57)
- 3 (2008-03-12 (水) 19:36:45)
- 4 (2008-03-14 (金) 21:44:03)
- 5 (2008-04-15 (火) 17:15:50)
- 6 (2008-04-25 (金) 19:33:36)
- 7 (2008-04-25 (金) 20:51:49)
- 8 (2008-05-14 (水) 13:45:47)
- 9 (2008-11-10 (月) 20:32:17)
- 10 (2011-04-20 (水) 18:41:16)
- 11 (2012-03-24 (土) 16:18:24)
- 12 (2013-01-30 (水) 23:42:27)
- 13 (2013-04-06 (土) 05:06:50)
- 14 (2013-05-09 (木) 11:37:00)
- 15 (2013-05-09 (木) 12:37:40)
- 16 (2013-05-26 (日) 05:34:28)
- 17 (2013-05-26 (日) 06:50:22)
- 18 (2013-07-26 (金) 01:38:05)
- 19 (2013-09-06 (金) 11:39:25)
- 20 (2013-09-21 (土) 20:44:23)
- 21 (2014-11-26 (水) 18:40:24)
- 22 (2014-11-28 (金) 16:29:51)
- 23 (2015-01-03 (土) 06:24:11)
- 24 (2015-03-24 (火) 21:23:15)
- 25 (2015-05-20 (水) 17:58:03)
- 26 (2015-12-08 (火) 15:15:47)
- 27 (2016-01-28 (木) 13:06:44)
- 28 (2016-09-02 (金) 12:34:08)
- 29 (2017-03-28 (火) 19:41:02)
- 30 (2017-03-29 (水) 13:52:49)
- 31 (2017-04-04 (火) 14:17:08)
- 32 (2017-06-07 (水) 15:35:06)
- 33 (2017-11-02 (木) 15:32:16)
- 34 (2018-02-09 (金) 19:19:55)
- 35 (2018-02-24 (土) 19:51:30)
- 36 (2018-02-27 (火) 14:23:21)
- 37 (2018-07-30 (月) 16:15:22)
- 38 (2019-05-28 (火) 20:30:42)
- 39 (2019-05-28 (火) 23:01:52)
- 40 (2021-02-18 (木) 06:58:08)
- 41 (2022-08-20 (土) 22:15:25)
- 42 (2024-02-03 (土) 13:51:56)
- 43 (2025-01-03 (金) 08:57:02)
- 44 (2025-01-03 (金) 09:01:23)
- 45 (2025-01-03 (金) 09:02:38)
- 46 (2025-01-03 (金) 09:03:21)
- 47 (2025-01-03 (金) 09:04:02)
- 48 (2025-06-19 (木) 12:41:37)
- 49 (2025-06-19 (木) 12:43:47)
TITLE:JInternalFrameをModalにする
Posted by aterai at 2007-10-15
JInternalFrameをModalにする
`JInternalFrame
を
Modal
にして、他の
JInternalFrame
`などを操作できないようにブロックします。
- &jnlp;
- &jar;
- &zip;
サンプルコード
//menuItem.setMnemonic(KeyEvent.VK_1);
class ModalInternalFrameAction1 extends AbstractAction {
public ModalInternalFrameAction1(String label) {
super(label);
}
@Override public void actionPerformed(ActionEvent e) {
setJMenuEnabled(false);
JOptionPane.showInternalMessageDialog(
desktop, "information", "modal1", JOptionPane.INFORMATION_MESSAGE);
setJMenuEnabled(true);
}
}
View in GitHub: Java, Kotlin//menuItem.setMnemonic(KeyEvent.VK_2);
class ModalInternalFrameAction2 extends AbstractAction {
private final JPanel glass = new MyGlassPane();
public ModalInternalFrameAction2(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);
}
@Override public void actionPerformed(ActionEvent e) {
setJMenuEnabled(false);
glass.setVisible(true);
JOptionPane.showInternalMessageDialog(
desktop, "information", "modal2", JOptionPane.INFORMATION_MESSAGE);
glass.setVisible(false);
setJMenuEnabled(true);
}
}
//menuItem.setMnemonic(KeyEvent.VK_3);
//Creating Modal Internal Frames -- Approach 1 and Approach 2
//http://java.sun.com/developer/JDCTechTips/2001/tt1220.html
class ModalInternalFrameAction3 extends AbstractAction {
private final Component orgGlassPane;
private final JPanel glass = new PrintGlassPane();
public ModalInternalFrameAction3(String label) {
super(label);
orgGlassPane = frame.getGlassPane();
glass.setVisible(false);
}
@Override public void actionPerformed(ActionEvent e) {
JOptionPane optionPane = new JOptionPane();
optionPane.setMessage("Hello, World");
optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
JInternalFrame modal = optionPane.createInternalFrame(desktop, "modal3");
removeSystemMenuListener(modal);
modal.addInternalFrameListener(new InternalFrameAdapter() {
@Override public void internalFrameClosed(InternalFrameEvent e) {
glass.setVisible(false);
frame.setGlassPane(orgGlassPane);
}
});
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) {}
}
}
解説
- Alt+1: `
JOptionPane.showInternalMessageDialog
メソッドを使用して、簡単なメッセージを表示する
Modal
な
Dialog
を
JDesktopPane
`内に表示- `
JButton
のマウスクリックは無効になるが、
Mnemonic
`が無効にならない- Alt+Bでボタンを押すことが出来てしまう
- `
Mnemonic
を設定したコンポーネントは
setEnabled(false)
`とする必要がある
- `
Mnemonic
を
JMenu
に設定していると
setEnabled(false)
`としても、Altキーに反応する- これは`
WindowsLookAndFeel
`だけ? - この`
InternalMessageDialog
を表示している間は、
JMenuBar
`をダミーと入れ替えて無効化
- これは`
- この`
InternalMessageDialog
`を閉じない限り、アプリケーションをAlt+F4などで閉じることは出来ない - `
InternalMessageDialog
`のシステムメニュー(左上のアイコンをクリックすると表示される)がマウスで操作不可能 - `
JToolTip
`は正常- `
showInternalMessageDialog(...)
メソッド内で、
pane.putClientProperty(PopupFactory_FORCE_HEAVYWEIGHT_POPUP, Boolean.TRUE)
(
JDK 1.6.0
の場合の
Key
は、
PopupFactory.forceHeavyWeightPopupKey
) されているため、
JComboBox
`などのドロップダウンメニューも正常
- `
- `
- Alt+2: Alt+1と同様に`
JOptionPane.showInternalMessageDialog
メソッドを使用し、かつ半透明な
GlassPane
を
JLayeredPane.MODAL_LAYER
`に追加- 動作、制限などは、Alt+2の`
InternalMessageDialog
`と同じ - `
JDesktopPane
`内にマスクが掛かる
- 動作、制限などは、Alt+2の`
- Alt+3: `
JFrame
に半透明な
GlassPane
を追加し、そこに
JInternalFrame
を追加することで
Modal
`に設定- `
JFrame
内全体(
JMenuBar
`なども含む)にマスクが掛かる - `
InternalMessageDialog
のシステムメニューが自身のレイヤーより奥に表示されるため、アイコン(
JLabel
`)をクリックしても反応しないようにリスナーを除去 - `
JComboBox
を
InternalMessageDialog
`に追加すると、そのドロップダウンメニューが裏に表示される - この`
InternalMessageDialog
`を開いていても、アプリケーションをAlt+F4などで閉じることが出来てしまう
- `
- Alt+3の方法で、`
InternalOptionDialog
に
JComboBox
を追加する場合、ドロップダウンメニューを正しく表示させるには、リフレクションを使って
ClientProperty
`を設定するしかない?- `
JInternalFrame#putClientProperty(PopupFactory_FORCE_HEAVYWEIGHT_POPUP, Boolean.TRUE)
とすれば、システムメニューも正常に表示されるが、
JOptionPane.showInternalXXXDialog
では、なぜか
JOptionPane
に設定するようになっている(
JInternalFrame
`は使い回ししているから?)
- `
JInternalFrame modal = optionPane.createInternalFrame(desktop, "modal3");
JComboBox combo = new JComboBox(new String[] {"Banana", "Apple", "Pear", "Grape"});
combo.setEditable(true);
try{
Field field;
if(System.getProperty("java.version").startsWith("1.6.0")) {
Class clazz = Class.forName("javax.swing.PopupFactory");
field = clazz.getDeclaredField("forceHeavyWeightPopupKey");
}else{ //1.7.0, 1.8.0
Class clazz = Class.forName("javax.swing.ClientPropertyKey");
field = clazz.getDeclaredField("PopupFactory_FORCE_HEAVYWEIGHT_POPUP");
}
field.setAccessible(true);
modal.putClientProperty(field.get(null), Boolean.TRUE);
}catch(Exception ex) {
ex.printStackTrace();
}
optionPane.setMessage(combo);
optionPane.setMessageType(JOptionPane.QUESTION_MESSAGE);
Alexander Potochkin's Blog: Disabling Swing Containers, the final solution?を参考に(`paint
ではなく、
print
が使用されている)して、
GlassPane
を以下のように修正すると、上記のサンプルのAlt+3(Alt+2の場合は、描画が乱れる)は、
Mnemonic
`もうまくブロックできるようです。
- `
JFrame
のメニューバーの
Mnemonic
`もブロックできる- `
JRootPane
から取得した
LayeredPane
が非表示なので、その子コンポーネント(
JMenuBar
や
ContentPane
`など)のキーイベントがすべて無効になる - JRootPane (Java Platform SE 6)の図にあるように、`
GlassPane
は、
JRootPane
の最上位の子コンポーネントなので、
LayeredPane
`を画像として表示している
- `
- `
JFrame
`のシステムメニューはブロックできない - モーダルにした`
JInternalFrame
`のシステムメニューは表示されない- ただし表示されないだけで、クリックしてからカーソル移動やダブルクリックなどが動いてしまう
- モーダルにした`
JInternalFrame
の右上の閉じるボタンの
JToolTip
が
JDesktopPane
内で表示される場合、空白になる
JDK 6
では
JToolTip
`は表示されない
class PrintGlassPane extends JPanel {
TexturePaint texture = TextureFactory.createCheckerTexture(4);
public PrintGlassPane() {
super((LayoutManager)null);
setOpaque(false);
}
@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/
// 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());
}
}
`JDK 6
`の場合、Disabled Glass Pane « Java Tips Weblogのようにキー入力を無効にするキーリスナーを追加する方法もあります。
この方法は、`JDK 5
などの場合、
WindowsLookAndFeel
`で、Altキーを押すとメニューバーにフォーカスが移ることがあります。
参考リンク
- Creating Modal Internal Frames -- Approach 1 and Approach 2
- How to Use Root Panes
- Disabling Swing Containers, the final solution?
コメント
JInternalFrameを半透明にすると、同様に`-- ateraiGlassPane
が
Ubuntu
(
GNOME
`)などで半透明にならない場合があります。- Alt+2で開いた場合、`
JInternalFrame
に
GlassPane
を乗せるのではなく、直接
JDesktopPane
の
JLayeredPane.MODAL_LAYER
`に追加するように変更しました。 -- aterai
- Alt+2で開いた場合、`
- メモ: Alexander Potochkin's Blog: Disabling Swing Containers, the final solution?のサンプルでは、`
Mnemonic
`もちゃんとブロックできているようなので、「あとで調べる & 参考にする」こと。 -- aterai - `
Mnemonic
`を数字キー(1, 2, 3)に変更 -- aterai - すべての`
Mnemonic
を一時的に無効化したい場合に、
UIManager.java
の
private static final String disableMnemonicKey = "swing.disablenavaids";
は使えない? 以下のように、
KeyboardFocusManager.setCurrentKeyboardFocusManager(...)
`で、Altキーなどを無視する方法もあるが…、もっと簡単な方法を調査中。 -- aterai
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
KeyboardFocusManager.setCurrentKeyboardFocusManager(new DefaultKeyboardFocusManager() {
@Override public boolean dispatchEvent(AWTEvent e) {
if(e instanceof KeyEvent) {
KeyEvent ke = (KeyEvent)e;
if((ke.getModifiers() & InputEvent.ALT_MASK) != 0) {
System.out.println("----\n"+ke);
return false;
}
}
return super.dispatchEvent(e);
}
});
JComboBox<String> combo = new JComboBox<>(new String[] {"Banana", "Apple", "Pear", "Grape"});
combo.setEditable(true);
JOptionPane.showInternalMessageDialog(
desktop, combo, "modal1", JOptionPane.INFORMATION_MESSAGE);
KeyboardFocusManager.setCurrentKeyboardFocusManager(manager);