• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:Menuに半透明の影を付ける
#navi(../)
RIGHT:Posted by [[terai]] at 2006-10-23
*Menuに半透明の影を付ける [#u32fd4be]
Posted by [[terai]] at 2006-10-23

#contents

**概要 [#e32024c1]
メニューに半透明の影を付けます。

//-&jnlp;
-&jar;
-&zip;

#screenshot

**サンプルコード [#eb189a65]
#code{{
public class CustomPopupMenuUI extends BasicPopupMenuUI {
  public static ComponentUI createUI(JComponent c) {
    return new CustomPopupMenuUI();
  }
  private static int OFF = 4;
  private static float ALPHA = 0.12f;
  public static JFrame frame = null;
  private static boolean isInRootPanel(JComponent popup, Point p) {
    if(frame==null) return false;
    Rectangle r = frame.getBounds();
    Dimension d = popup.getPreferredSize();
    return r.contains(p.x, p.y, d.width+OFF, d.height+OFF);
  private static boolean isHeavyWeightContainer(Component contents) {
    for(Container p=contents.getParent();p!=null;p=p.getParent()) {
      if((p instanceof JWindow) || (p instanceof Panel)) {
        return true;
      }
    }
    return false;
  }
  public Popup getPopup(JPopupMenu popup, int x, int y) {
    Popup pp = super.getPopup(popup,x,y);
    JPanel panel = (JPanel)popup.getParent();
    Point p = new Point(x, y);
    if(isInRootPanel(panel, p)) {
      //System.out.println("inner");
      panel.setBorder(new ShadowBorderInPanel());
    if(isHeavyWeightContainer(panel)) {
        System.out.println("outer");
        Point p = new Point(x,y);
        panel.setBorder(new ShadowBorder(panel,p));
    }else{
      //System.out.println("outer");
      panel.setBorder(new ShadowBorder(panel,p));
        System.out.println("inner");
        panel.setBorder(new ShadowBorderInPanel());
    }
    panel.setOpaque(false);
    return pp;
  }
//......
}}

**解説 [#d73e76f4]
上記のサンプルでは、BasicPopupMenuUI を継承した、CustomPopupMenuUI を作成して、これをUIManagerに登録しています。
#code{{
CustomPopupMenuUI.frame = frame;
UIManager.put("PopupMenuUI","example.CustomPopupMenuUI");
}}

この CustomPopupMenuUI では、ポップアップメニューがフレームの中にあるか外にあるかで、影のつけ方を切り替えています。外にある場合は、Robot を使って画面をキャプチャしています。

メニューがフレームの外にはみ出す場合に、メニューをすばやく切り替えたりすると、ゴミが残ることがあるようです。参考リンクのcontrib.com.jgoodies.looks.common.ShadowPopupFactory を使っても同様のゴミが出る場合があります。
%%メニューがフレームの外にはみ出す場合に、メニューをすばやく切り替えたりすると、ゴミが残ることがあるようです。参考リンクのcontrib.com.jgoodies.looks.common.ShadowPopupFactory を使っても同様のゴミが出る場合があります。%% 再現しなくなった?ようです。

substance のソースに添付されていた contrib.com.jgoodies.looks.common.ShadowPopupFactory も、src.zipに添付しています((ライセンスは大丈夫?))。テストする場合は、以下のように設定してみてください。
#code{{
//CustomPopupMenuUI.frame = frame;
//UIManager.put("PopupMenuUI","example.CustomPopupMenuUI");
contrib.com.jgoodies.looks.common.ShadowPopupFactory.install();
}}

**参考リンク [#w4e129d8]
- [[Java Swing Hacks #11 ドロップシャドウ付きのメニューを作る>http://www.oreilly.co.jp/books/4873112788/toc.html]]
- [[substance: Substance Java look and feel - main page>https://substance.dev.java.net/]]
-- contrib.com.jgoodies.looks.common.ShadowPopupFactory
-[[JPopupMenuに半透明の影を付ける>Swing/DropShadowPopup]]

**コメント [#r700cff6]
- ポップアップメニューがフレーム内にあるかどうかではなく、HeavyWeightContainerかどうかで影のつけ方を切り替えるように変更。 -- [[terai]] &new{2008-05-29 (木) 16:13:30};

#comment