Swing/TranslucentSubMenu の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/TranslucentSubMenu へ行く。
- Swing/TranslucentSubMenu の差分を削除
--- category: swing folder: TranslucentSubMenu title: JMenuなどから開くPopupMenuを半透明化 tags: [JMenu, JMenuItem, JPopupMenu, Translucent] author: aterai pubdate: 2012-10-22T18:38:06+09:00 description: JPopupMenuの親のJWindow、JMenuやJMenuItemなどを透明にして、JPopupMenuを半透明にします。 image: https://lh5.googleusercontent.com/-MKRZgWcSrRw/UIT3NRGfX9I/AAAAAAAABUk/fOYdfJmIt4g/s800/TranslucentSubMenu.png --- * 概要 [#summary] `JPopupMenu`の親の`JWindow`、`JMenu`や`JMenuItem`などを透明にして、`JPopupMenu`を半透明にします。 #download(https://lh5.googleusercontent.com/-MKRZgWcSrRw/UIT3NRGfX9I/AAAAAAAABUk/fOYdfJmIt4g/s800/TranslucentSubMenu.png) * サンプルコード [#sourcecode] #code(link){{ class TransparentMenu extends JMenu { private JPopupMenu popupMenu; public TransparentMenu(String title) { super(title); } // https://bugs.openjdk.java.net/browse/JDK-4688783 // https://bugs.openjdk.org/browse/JDK-4688783 private void ensurePopupMenuCreated() { if (popupMenu == null) { this.popupMenu = new TranslucentPopupMenu(); popupMenu.setInvoker(this); popupListener = createWinListener(popupMenu); } } @Override public JPopupMenu getPopupMenu() { ensurePopupMenuCreated(); return popupMenu; } @Override public JMenuItem add(JMenuItem menuItem) { ensurePopupMenuCreated(); menuItem.setOpaque(false); return popupMenu.add(menuItem); } @Override public Component add(Component c) { ensurePopupMenuCreated(); if (c instanceof JComponent) { ((JComponent) c).setOpaque(false); } popupMenu.add(c); return c; } @Override public void addSeparator() { ensurePopupMenuCreated(); popupMenu.addSeparator(); } @Override public void insert(String s, int pos) { if (pos < 0) { throw new IllegalArgumentException("index less than zero."); } ensurePopupMenuCreated(); popupMenu.insert(new JMenuItem(s), pos); } @Override public JMenuItem insert(JMenuItem mi, int pos) { if (pos < 0) { throw new IllegalArgumentException("index less than zero."); } ensurePopupMenuCreated(); popupMenu.insert(mi, pos); return mi; } @Override public void insertSeparator(int index) { if (index < 0) { throw new IllegalArgumentException("index less than zero."); } ensurePopupMenuCreated(); popupMenu.insert(new JPopupMenu.Separator(), index); } @Override public boolean isPopupMenuVisible() { ensurePopupMenuCreated(); return popupMenu.isVisible(); } } }} * 解説 [#explanation] 上記のサンプルでは、`JMenu`を継承する`TransparentMenu`を作成して`JMenu`自身と子の`JMenuItem`などを透明化しています。また`JMenu`から開く`JPopupMenu`も[[JPopupMenuを半透明にする>Swing/TranslucentPopupMenu]]を使用して半透明になるよう設定しています。 - [http://today.java.net/pub/a/today/2008/03/18/translucent-and-shaped-swing-windows.html Translucent and Shaped Swing Windows | Java.net] を参考に `PopupFactory#getPopup(...)`をオーバーライドし、常に`JPopupMenu`(半透明)の親に`JWindow`(完全に透明、`Heavy weight`)を使用するように設定 #code{{ PopupFactory.setSharedInstance(new TranslucentPopupFactory()); // ... class TranslucentPopupFactory extends PopupFactory { @Override public Popup getPopup(Component owner, Component contents, int x, int y) throws IllegalArgumentException { return new TranslucentPopup(owner, contents, x, y); } } }} ---- - [[JPopupMenuを半透明にする>Swing/TranslucentPopupMenu]]では、`JPopupMenu#show(...)`メソッドをオーバーライドすることでポップアップが親フレームからはみ出して`Heavy weight`の`JWindow`が`JPopupMenu`の親となる場合のみ`JWindow#setBackground(ALPHA_ZERO)`などで透明化(`JPopupMenu`は半透明) -- [https://bugs.openjdk.java.net/browse/JDK-7156657 Bug ID: 7156657 Version 7 doesn't support translucent popup menus against a translucent window] が原因?で`1.7.0_06`以前ではサブメニューが半透明化されない場合がある -- [https://bugs.openjdk.org/browse/JDK-7156657 Bug ID: 7156657 Version 7 doesn't support translucent popup menus against a translucent window] が原因?で`1.7.0_06`以前ではサブメニューが半透明化されない場合がある -- `PopupFactory.setSharedInstance(new TranslucentPopupFactory())`を使用する場合はバグの影響を受けない -- 上記のバグ?以外にも、[[JPopupMenuを半透明にする>Swing/TranslucentPopupMenu]]でサブメニューを半透明にする場合、`Heavy weight`の`JPopupMenu`に使用する`JWindow`の`ContentPane`と`JRootPane`の不透明設定(`isOpaque()`)に注意する必要がある ---- HeavyWeightWindow: win0, JPopupMenu: base javax.swing.JPanel: false javax.swing.JLayeredPane: false javax.swing.JRootPane: false ---- HeavyWeightWindow: win1, JPopupMenu: sub javax.swing.JPanel: true javax.swing.JLayeredPane: false javax.swing.JRootPane: true #code{{ class TranslucentPopupMenu extends JPopupMenu { @Override public void show(Component c, int x, int y) { EventQueue.invokeLater(new Runnable() { @Override public void run() { Window p = SwingUtilities.getWindowAncestor(TranslucentPopupMenu.this); if (p != null && p instanceof JWindow) { JWindow w = (JWindow) p; w.setBackground(ALPHA_ZERO); System.out.format("HeavyWeightWindow: %s, JPopupMenu: %s\n", w.getName(), getName()); Container c = (Container) w.getContentPane(); while (c != null && c instanceof JComponent) { JComponent jc = (JComponent) c; System.out.format("%s: %s\n", c.getClass().getName(), jc.isOpaque()); if (jc.isOpaque()) { jc.setOpaque(false); } c = c.getParent(); } } else { System.out.println("Light weight"); } } }); super.show(c, x, y); } @Override protected void paintComponent(Graphics g) { // ... }} * 参考リンク [#reference] - [http://today.java.net/pub/a/today/2008/03/18/translucent-and-shaped-swing-windows.html Translucent and Shaped Swing Windows | Java.net] - [https://bugs.openjdk.java.net/browse/JDK-7156657 JDK-7156657 Version 7 doesn't support translucent popup menus against a translucent window] - [https://bugs.openjdk.org/browse/JDK-7156657 JDK-7156657 Version 7 doesn't support translucent popup menus against a translucent window] - [[JPopupMenuを半透明にする>Swing/TranslucentPopupMenu]] - [[JRootPaneの背景として画像を表示>Swing/RootPaneBackground]] * コメント [#comment] #comment #comment