Swing/RoundedCornerPopupMenu のバックアップ(No.1)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/RoundedCornerPopupMenu へ行く。
- 1 (2024-01-22 (月) 05:58:15)
- category: swing folder: RoundedCornerPopupMenu title: JPopupMenuの角を丸める tags: [JPopupMenu, Border, JMenu] author: aterai pubdate: 2024-01-22T05:56:34+09:00 description: JPopupMenuの背景を透明化し、これに角丸Borderを設定します。 image: https://drive.google.com/uc?id=1UcaF0qHBjIuO-hIGwMbyCBGBm4T6OqBl
概要
JPopupMenuの背景を透明化し、これに角丸Borderを設定します。
Screenshot
Advertisement
サンプルコード
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
UIManager.put("PopupMenuUI", "example.RoundedPopupMenuUI");
// ...
public final class RoundedPopupMenuUI extends BasicPopupMenuUI {
public static ComponentUI createUI(JComponent c) {
return new RoundedPopupMenuUI();
}
@Override public Popup getPopup(JPopupMenu popup, int x, int y) {
Popup pp = super.getPopup(popup, x, y);
if (pp != null) {
EventQueue.invokeLater(() -> {
Window w = SwingUtilities.getWindowAncestor(popup);
if (w != null && w.getType() == Window.Type.POPUP) {
w.setBackground(new Color(0x0, true));
}
});
popup.setBorder(new RoundedBorder());
popup.setOpaque(false);
}
return pp;
}
}
class RoundedBorder extends AbstractBorder {
@Override public Insets getBorderInsets(Component c) {
return new Insets(5, 5, 5, 5);
}
@Override public void paintBorder(
Component c, Graphics g, int x, int y, int w, int h) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(c.getBackground());
Shape s = makeShape((JComponent) c);
g2.fill(s);
g2.setPaint(Color.GRAY);
g2.draw(s);
g2.dispose();
}
private static Shape makeShape(JComponent c) {
float w = c.getWidth() - 1f;
float h = c.getHeight() - 1f;
Insets i = c.getInsets();
float r = Math.min(i.top + i.left, i.bottom + i.right);
return new RoundRectangle2D.Float(0f, 0f, w, h, r, r);
}
}
View in GitHub: Java, Kotlin解説
BasicPopupMenuUI#getPopup(...)
をオーバーライドしてJPopupMenu
の背景を透明化するRoundedPopupMenuUI
を作成- 親
JFrame
内に表示される場合はJPopupMenu#setOpaque(false)
で透明化が可能 - 親
JFrame
外に表示される場合はJPopupMenu#setOpaque(false)
に加えて、その親となる重量コンポーネントのWindow
の背景も透明化する必要がある
- 親
RoundRectangle2D.Float(...)
で作成したラウンド矩形を表示するBorder
を透明化したJPopupMenu
に設定UIManager.put("PopupMenuUI", "example.RoundedPopupMenuUI")
でJMenu
から開く場合を含めたすべてのJPopupMenu
がRoundedPopupMenuUI
を使用するよう設定
- 特定の
JPopupMenu
のみ角を丸めたい場合は、直接以下のメソッドをオーバーライドしたJPopupMenu
を使用する方法があるJPopupMenu#isOpaque()
をオーバーライドして自身を透明化JPopupMenu#show(...)
をオーバーライドして親Popup$HeavyWeightWindow
を透明化JPopupMenu#paintComponent(...)
をオーバーライドしてラウンド矩形を描画
final class RoundedPopupMenu extends JPopupMenu {
@Override public void updateUI() {
setBorder(null);
super.updateUI();
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
}
@Override public boolean isOpaque() {
return false;
}
@Override protected void paintComponent(Graphics g) {
// super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(getBackground());
Shape s = makeShape();
g2.fill(s);
g2.setPaint(Color.GRAY);
g2.draw(s);
g2.dispose();
}
@Override public void show(Component c, int x, int y) {
EventQueue.invokeLater(() -> {
Window top = SwingUtilities.getWindowAncestor(this);
// Popup$HeavyWeightWindow
if (top != null && top.getType() == Window.Type.POPUP) {
top.setBackground(new Color(0x0, true));
}
});
super.show(c, x, y);
}
private Shape makeShape() {
float w = getWidth() - 1f;
float h = getHeight() - 1f;
Insets i = getInsets();
float r = Math.min(i.top + i.left, i.bottom + i.right);
return new RoundRectangle2D.Float(0f, 0f, w, h, r, r);
}
}