Swing/TranslucentSubMenu のバックアップ(No.10)
- バックアップ一覧
 - 差分 を表示
 - 現在との差分 を表示
 - 現在との差分 - Visual を表示
 - ソース を表示
 - Swing/TranslucentSubMenu へ行く。
  
- 1 (2012-10-22 (月) 18:38:06)
 - 2 (2012-10-22 (月) 20:22:51)
 - 3 (2012-12-06 (木) 12:15:23)
 - 4 (2012-12-07 (金) 16:40:20)
 - 5 (2012-12-25 (火) 23:11:35)
 - 6 (2012-12-26 (水) 11:24:59)
 - 7 (2014-11-01 (土) 00:46:09)
 - 8 (2014-12-11 (木) 15:09:07)
 - 9 (2015-02-22 (日) 21:04:31)
 - 10 (2016-07-20 (水) 20:33:11)
 - 11 (2017-09-27 (水) 19:04:28)
 - 12 (2017-11-02 (木) 15:34:40)
 - 13 (2019-05-22 (水) 19:35:38)
 - 14 (2019-06-11 (火) 19:44:14)
 - 15 (2021-02-24 (水) 06:02:07)
 - 16 (2022-08-20 (土) 22:15:25)
 - 17 (2025-01-03 (金) 08:57:02)
 - 18 (2025-01-03 (金) 09:01:23)
 - 19 (2025-01-03 (金) 09:02:38)
 - 20 (2025-01-03 (金) 09:03:21)
 - 21 (2025-01-03 (金) 09:04:02)
 - 22 (2025-06-19 (木) 12:41:37)
 - 23 (2025-06-19 (木) 12:43:47)
 
 
- title: JMenuなどから開くPopupMenuを半透明化 tags: [JMenu, JMenuItem, JPopupMenu, Translucent] author: aterai pubdate: 2012-10-22T18:38:06+09:00 description: JPopupMenuの親のJWindow、JMenuやJMenuItemなどを透明にして、JPopupMenuを半透明にします。
 
概要
JPopupMenuの親のJWindow、JMenuやJMenuItemなどを透明にして、JPopupMenuを半透明にします。
Screenshot

Advertisement
サンプルコード
class TransparentMenu extends JMenu {
  public TransparentMenu(String title) {
    super(title);
  }
  //http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4688783
  private JPopupMenu popupMenu;
  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();
  }
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、JMenuを継承するTransparentMenuを作成して、自身とJMenuItemなどを透明化し、JMenuから開くJPopupMenuは、JPopupMenuを半透明にするを使用して半透明にしています。
- Translucent and Shaped Swing Windows | Java.net を参考に 
PopupFactory#getPopup(...)をオーバーライドし、常にJPopupMenu(半透明)の親にJWindow(完全に透明、Heavy weight)を使用するように設定 
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を半透明にするでは、
JPopupMenu#show(...)メソッドをオーバーライドし、ポップアップが親フレームからはみ出してHeavy weightのJWindowがJPopupMenuの親となる場合のみ、JWindow#setBackground(ALPHA_ZERO)などで透明化(JPopupMenuは半透明)- Bug ID: 7156657 Version 7 doesn't support translucent popup menus against a translucent window が原因?で、
1.7.0_06以前では、サブメニューが半透明化されない場合がある PopupFactory.setSharedInstance(new TranslucentPopupFactory())を使用する場合はバグの影響を受けない- 上記のバグ?以外にも、JPopupMenuを半透明にするでサブメニューを半透明にする場合、
Heavy weightのJPopupMenuに使用するJWindowのContentPaneとJRootPaneの不透明設定(isOpaque())に注意する必要がある 
 - Bug ID: 7156657 Version 7 doesn't support translucent popup menus against a translucent window が原因?で、
 
---- 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
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) {
//...
参考リンク
- Translucent and Shaped Swing Windows | Java.net
 - Bug ID: 7156657 Version 7 doesn't support translucent popup menus against a translucent window
 - JPopupMenuを半透明にする