TITLE:JPopupMenuに半透明の影を付ける
#navi(../)
*JPopupMenuに半透明の影を付ける [#z6537cfc]
Posted by [[terai]] at 2006-07-03

#contents

**概要 [#qe9dac90]
Robotで画面をキャプチャーするなどして、半透明の影をJPopupMenuに付けます。

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

#screenshot

**サンプルコード [#q20cf4f0]
#code{{
class ShadowBorder extends AbstractBorder {
  private final int xoff, yoff;
  private final Insets insets;
  protected BufferedImage screenShot = null;
  public ShadowBorder(int x, int y, JComponent c, Point p) {
    this.xoff = x;
    this.yoff = y;
    this.insets = new Insets(0,0,xoff,yoff);
    try{
      Robot robot = new Robot();
      Dimension d = c.getPreferredSize();
      Rectangle rect = new Rectangle(p.x, p.y, d.width+x, d.height+y);
      screenShot = robot.createScreenCapture(rect);
    }catch (java.awt.AWTException ex) {}
  }
  public Insets getBorderInsets(Component c) {
    return insets;
  }
  public void paintBorder(Component comp, Graphics g,
                          int x, int y, int w, int h) {
    if(screenShot==null) return;
    BufferedImage shadow = new BufferedImage(w, h,
                                             BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = shadow.createGraphics();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setComposite(AlphaComposite.getInstance(
                      AlphaComposite.SRC_OVER,0.2f));
    g2.setPaint(Color.BLACK);
    for(int i=0;i<xoff;i++) {
      g2.fillRoundRect(xoff, xoff, w-xoff-xoff+i, h-xoff-xoff+i, 10,10);
    }
    g2.dispose();
    Graphics2D gx = (Graphics2D) g;
    gx.drawImage(screenShot, 0, 0, comp);
    gx.drawImage(shadow, 0, 0, comp);
  }
}
}}

**解説 [#te55e54d]
ポップアップメニューに半透明の影をつける際、フレームからはみ出すかどうかで異なる処理を行っています。

上記のサンプルコードは、フレームからはみ出す場合に使用するBorderクラスです。

-フレーム内
--JPopupMenu#paintComponentメソッドで半透明の影を描画しています。

-フレーム外
--Robotを使って画面全体をキャプチャーし、これを利用して半透明の影をBorderとして作成しています。このためポップアップメニューがはみ出しても、影を付けることができますが、多少時間が掛かります。

**参考リンク [#jb8cc361]
-[[Menuに半透明の影を付ける>Swing/MenuWithShadow]]

**コメント [#e88a4825]
- キャプチャーが遅いのは画面全体を撮っているからで、必要なサイズだけにすれば結構速いようです。サンプルを修正してみたところ、毎回キャプチャするようにしても特に気にならない速度で動いてます。 -- [[terai]] &new{2006-07-18 (火) 12:02:13};
- ソース中でisInRootPanelがおかしい気がするのですが・・・ 
//convertPointToScreenga -- [[sawshun]] &new{2006-10-05 (木) 11:20:25};
//- #改行しようとしたらコメント入ってしまいました  
// コメント勝手に修正しました(terai)
convertPointToScreenがいらないのと return r.contains(pt)&&r.contains(p) にしないとフレーム内の判定がおかしいようです -- [[sawshun]] &new{2006-10-05 (木) 11:23:39};
-- ご指摘ありがとうごさいます。convertPointToScreenを削除して、MyPopupMenu#isInRootPanelは以下のように修正しました。 -- [[terai]] &new{2006-10-05 (木) 12:34:12};
#code{{
private boolean isInRootPanel(JComponent root, Point p) {
  Rectangle r = root.getBounds();
  Dimension d = this.getPreferredSize();
  //pointed out by sawshun
  return r.contains(p.x, p.y, d.width+off, d.height+off);
}
}}

#comment