Path2Dで額縁風の図形を作成しBorderとして使用する
Total: 441
, Today: 1
, Yesterday: 2
Posted by aterai at
Last-modified:
概要
Path2D
のベジェ曲線を使用して角を内側に丸めた額縁風の図形を描画するBorder
を作成し、JTextField
などのコンポーネントに設定します。
Screenshot
Advertisement
サンプルコード
JScrollPane scroll = new JScrollPane(new JTable(8, 5)) {
private static final int ARC = 8;
@Override protected void paintComponent(Graphics g) {
Border b = getBorder();
if (!isOpaque() && b instanceof PlaqueBorder) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(getBackground());
int w = getWidth() - 1;
int h = getHeight() - 1;
g2.fill(((PlaqueBorder) b).getBorderShape(0, 0, w, h, ARC));
g2.dispose();
}
super.paintComponent(g);
}
@Override public void updateUI() {
super.updateUI();
setOpaque(false);
setBackground(Color.WHITE);
getViewport().setBackground(getBackground());
setBorder(new PlaqueBorder(ARC) {
@Override protected Shape getBorderShape(
double x, double y, double w, double h, double r) {
double rr = r * .5522;
Path2D path = new Path2D.Double();
path.moveTo(x, y + r);
path.curveTo(
x + rr, y + r, x + r, y + rr, x + r, y);
path.lineTo(x + w - r, y);
path.curveTo(
x + w - r, y + rr, x + w - rr, y + r, x + w, y + r);
path.lineTo(x + w, y + h - r);
path.curveTo(
x + w - rr, y + h - r, x + w - r, y + h - rr, x + w - r, y + h);
path.lineTo(x + r, y + h);
path.curveTo(
x + r, y + h - rr, x + rr, y + h - r, x, y + h - r);
path.closePath();
return path;
}
});
}
};
View in GitHub: Java, Kotlin解説
Path2D#curveTo(...)
EmptyBorder
を継承するPlaqueBorder
を作成PlaqueBorder#paintBorder(...)
をオーバーライドしてその余白にPath2D#curveTo(...)
とPath2D#lineTo(...)
で作成した額縁風の図形を描画- 余白内に線を描画するので内部のコンポーネントとは交差しない
- 角のラウンド半径は
PlaqueBorder#getBorderInsets().top
の値を使用 Path2D#curveTo(...)
で使用する制御点は頂点から半径の0.55228…
倍(4d * (Math.sqrt(2d) - 1d) / 3d
)の位置を使用
Area#subtract(...)
Rectangle2D
で作成した矩形の4
隅をEllipse2D
で切り取って額縁風の図形を作成JTextField#paintComponent(...)
をオーバーライドしてPlaqueBorder
の図形内のみ背景を描画し、角丸の外側部分はJTextFieldの角を丸める同様透明化
class PlaqueBorder extends EmptyBorder {
protected PlaqueBorder(int arc) {
super(arc, arc, arc, arc);
}
@Override public void paintBorder(
Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.GRAY);
Insets i = getBorderInsets(c);
int arc = Math.min(i.top, Math.min(width / 2, height / 2));
g2.draw(getBorderShape(x, y, width - 1d, height - 1d, arc));
g2.dispose();
}
protected Shape getBorderShape(
double x, double y, double w, double h, double r) {
Area rect = new Area(new Rectangle2D.Double(x, y, w, h));
rect.subtract(new Area(new Ellipse2D.Double(
x - r, y - r, r + r, r + r)));
rect.subtract(new Area(new Ellipse2D.Double(
x + w - r, y - r, r + r, r + r)));
rect.subtract(new Area(new Ellipse2D.Double(
x - r, y + h - r, r + r, r + r)));
rect.subtract(new Area(new Ellipse2D.Double(
x + w - r, y + h - r, r + r, r + r)));
return rect;
}
}
参考リンク
- JTextFieldの角を丸める
- ベジェ曲線による円の描画の制御点の位置はなぜ0.55228…なのか?
- geometry - How to create circle with Bézier curves? - Stack Overflow