概要
Robot
で画面をキャプチャーするなどして、半透明の影をJPopupMenu
に付けます。
サンプルコード
class ShadowBorder extends AbstractBorder {
private final int xoff, yoff;
private final transient BufferedImage screen;
private transient BufferedImage shadow;
public ShadowBorder(int x, int y, JComponent c, Point p) {
super();
this.xoff = x;
this.yoff = y;
BufferedImage bi = null;
try {
Robot robot = new Robot();
Dimension d = c.getPreferredSize();
bi = robot.createScreenCapture(
new Rectangle(p.x, p.y, d.width + xoff, d.height + yoff));
} catch (AWTException ex) {
ex.printStackTrace();
}
screen = bi;
}
@Override public Insets getBorderInsets(Component c) {
return new Insets(0, 0, xoff, yoff);
}
@Override public void paintBorder(
Component c, Graphics g, int x, int y, int w, int h) {
if (screen == null) {
return;
}
if (shadow == null || shadow.getWidth() != w || shadow.getHeight() != h) {
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, .2f));
g2.setPaint(Color.BLACK);
for (int i = 0; i < xoff; i++) {
g2.fillRoundRect(xoff, xoff, w - xoff - xoff + i, h - xoff - xoff + i, 4, 4);
}
g2.dispose();
}
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(screen, 0, 0, c);
g2d.drawImage(shadow, 0, 0, c);
g2d.setPaint(c.getBackground()); //??? 1.7.0_03
g2d.fillRect(x, y, w - xoff, h - yoff);
g2d.dispose();
}
}
view all解説
ポップアップメニューに半透明の影をつける際、フレームからはみ出すかどうかで異なる処理を行っています。
上記のサンプルコードは、フレームからはみ出す場合に使用するBorder
クラスです。
- フレーム内
JPopupMenu#paintComponent
メソッドで半透明の影を描画
- フレーム外
Robot
を使って画面全体をキャプチャーし、これを利用して半透明の影をBorder
として作成- このためポップアップメニューがはみ出しても、影を付けることが可能
JDK 1.7.0
や、1.6.0_10
以上の場合、フレーム外でもRobot
を使用せず、以下のようにJPopupMenu
の上位Window
の背景色を透明にすれば影の描画が可能です。
class DropShadowPopupMenu extends JPopupMenu {
private static final int OFFSET = 4;
private transient BufferedImage shadow;
private Border border;
@Override public boolean isOpaque() {
return false;
}
@Override public void updateUI() {
setBorder(null);
super.updateUI();
border = null;
}
@Override protected void paintComponent(Graphics g) {
//super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.drawImage(shadow, 0, 0, this);
g2.setPaint(getBackground()); //??? 1.7.0_03
g2.fillRect(0, 0, getWidth() - OFFSET, getHeight() - OFFSET);
g2.dispose();
}
@Override public void show(Component c, int x, int y) {
if (border == null) {
Border inner = getBorder();
Border outer = BorderFactory.createEmptyBorder(0, 0, OFFSET, OFFSET);
border = BorderFactory.createCompoundBorder(outer, inner);
}
setBorder(border);
Dimension d = getPreferredSize();
int w = d.width;
int h = d.height;
if (shadow == null || shadow.getWidth() != w || shadow.getHeight() != h) {
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, .2f));
g2.setPaint(Color.BLACK);
for (int i = 0; i < OFFSET; i++) {
g2.fillRoundRect(
OFFSET, OFFSET, w - OFFSET - OFFSET + i, h - OFFSET - OFFSET + i, 4, 4);
}
g2.dispose();
}
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
Window pop = SwingUtilities.getWindowAncestor(DropShadowPopupMenu.this);
if (pop instanceof JWindow) {
pop.setBackground(new Color(0x0, true)); //JDK 1.7.0
}
}
});
super.show(c, x, y);
}
}