Rounded LineBorder - 不是所有的角都是圆的
Rounded LineBorder - not all corners are rounded
我正在使用 JFreeChart
,我想通过创建自己的 Class
来自定义 ToolTip
,它扩展 ChartPanel
并覆盖 createToolTip()
。
static private class PrivateChartPanel extends ChartPanel{
//constructors
@Override
public JToolTip createToolTip() {
JToolTip jtt = super.createToolTip();
jtt.setBackground(Color.WHITE);
jtt.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
return jtt;
}
}
问题出在 Border
。它不是在所有角落都是圆形的。
为什么它不是所有角都是圆的,我是怎么做到的?
P.S.: 我新建了一个简单的项目
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class HelloWorld {
public static void main(String[] args) {
JFrame a = new JFrame();
a.setBounds(100, 100, 100, 100);
a.setLayout(null);
JPanel b = new JPanel();
b.setBounds(5, 5, 50, 50);
b.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
a.add(b);
a.setVisible(true);
}
}
JPanel 的 Border 也有同样的问题。我正在使用 Java 10
圆角的效果取决于这些圆角的大小。在LineBorder
的情况下,由thickness
属性决定。相关的实现代码是这样的:
int offs = this.thickness;
int size = offs + offs;
if (this.roundedCorners) {
float arc = .2f * offs;
outer = new RoundRectangle2D.Float(x, y, width, height, offs, offs);
inner = new RoundRectangle2D.Float(x + offs, y + offs, width - size, height - size, arc, arc);
}
else {
outer = new Rectangle2D.Float(x, y, width, height);
inner = new Rectangle2D.Float(x + offs, y + offs, width - size, height - size);
}
Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
path.append(outer, false);
path.append(inner, false);
g2d.fill(path);
所以它区分了内角和外角,对于1的线宽意义不大。但更糟糕的是,外角大小仅为 offs
,与 thickness
(在您的情况下为一个)相同,而内圆角的大小由 arc
决定,即.2f * offs
。对于您的 thickness
个,生成的内角大小为 0.2
。所以我们在左上角看到一个效果似乎纯属巧合(这两个不同角的圆角问题),因为即使一个更大的外角尺寸也不足以产生可见的圆角效果。
这是 20
的 thickness
的样子,结果是 20
的外角尺寸和 4
的巨大内角尺寸:
不知道 Swing 开发人员在此 class 中添加圆角支持时考虑的实际用例是什么。我无法想象这种策略在任何情况下都有用。
实施有意义的 Border
并不难。一种可能的实现方式如下:
public class RoundedLineBorder extends AbstractBorder {
int lineSize, cornerSize;
Paint fill;
Stroke stroke;
private Object aaHint;
public RoundedLineBorder(Paint fill, int lineSize, int cornerSize) {
this.fill = fill;
this.lineSize = lineSize;
this.cornerSize = cornerSize;
stroke = new BasicStroke(lineSize);
}
public RoundedLineBorder(Paint fill, int lineSize, int cornerSize, boolean antiAlias) {
this.fill = fill;
this.lineSize = lineSize;
this.cornerSize = cornerSize;
stroke = new BasicStroke(lineSize);
aaHint = antiAlias? RenderingHints.VALUE_ANTIALIAS_ON: RenderingHints.VALUE_ANTIALIAS_OFF;
}
@Override
public Insets getBorderInsets(Component c, Insets insets) {
int size = Math.max(lineSize, cornerSize);
if(insets == null) insets = new Insets(size, size, size, size);
else insets.left = insets.top = insets.right = insets.bottom = size;
return insets;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D)g;
Paint oldPaint = g2d.getPaint();
Stroke oldStroke = g2d.getStroke();
Object oldAA = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
try {
g2d.setPaint(fill!=null? fill: c.getForeground());
g2d.setStroke(stroke);
if(aaHint != null) g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, aaHint);
int off = lineSize >> 1;
g2d.drawRoundRect(x+off, y+off, width-lineSize, height-lineSize, cornerSize, cornerSize);
}
finally {
g2d.setPaint(oldPaint);
g2d.setStroke(oldStroke);
if(aaHint != null) g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAA);
}
}
}
现在,当我更改线路时
b.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
在你的例子中
b.setBorder(new RoundedLineBorder(Color.BLACK, 1, 10, true));
我明白了
我正在使用 JFreeChart
,我想通过创建自己的 Class
来自定义 ToolTip
,它扩展 ChartPanel
并覆盖 createToolTip()
。
static private class PrivateChartPanel extends ChartPanel{
//constructors
@Override
public JToolTip createToolTip() {
JToolTip jtt = super.createToolTip();
jtt.setBackground(Color.WHITE);
jtt.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
return jtt;
}
}
问题出在 Border
。它不是在所有角落都是圆形的。
为什么它不是所有角都是圆的,我是怎么做到的?
P.S.: 我新建了一个简单的项目
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class HelloWorld {
public static void main(String[] args) {
JFrame a = new JFrame();
a.setBounds(100, 100, 100, 100);
a.setLayout(null);
JPanel b = new JPanel();
b.setBounds(5, 5, 50, 50);
b.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
a.add(b);
a.setVisible(true);
}
}
JPanel 的 Border 也有同样的问题。我正在使用 Java 10
圆角的效果取决于这些圆角的大小。在LineBorder
的情况下,由thickness
属性决定。相关的实现代码是这样的:
int offs = this.thickness;
int size = offs + offs;
if (this.roundedCorners) {
float arc = .2f * offs;
outer = new RoundRectangle2D.Float(x, y, width, height, offs, offs);
inner = new RoundRectangle2D.Float(x + offs, y + offs, width - size, height - size, arc, arc);
}
else {
outer = new Rectangle2D.Float(x, y, width, height);
inner = new Rectangle2D.Float(x + offs, y + offs, width - size, height - size);
}
Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
path.append(outer, false);
path.append(inner, false);
g2d.fill(path);
所以它区分了内角和外角,对于1的线宽意义不大。但更糟糕的是,外角大小仅为 offs
,与 thickness
(在您的情况下为一个)相同,而内圆角的大小由 arc
决定,即.2f * offs
。对于您的 thickness
个,生成的内角大小为 0.2
。所以我们在左上角看到一个效果似乎纯属巧合(这两个不同角的圆角问题),因为即使一个更大的外角尺寸也不足以产生可见的圆角效果。
这是 20
的 thickness
的样子,结果是 20
的外角尺寸和 4
的巨大内角尺寸:
不知道 Swing 开发人员在此 class 中添加圆角支持时考虑的实际用例是什么。我无法想象这种策略在任何情况下都有用。
实施有意义的 Border
并不难。一种可能的实现方式如下:
public class RoundedLineBorder extends AbstractBorder {
int lineSize, cornerSize;
Paint fill;
Stroke stroke;
private Object aaHint;
public RoundedLineBorder(Paint fill, int lineSize, int cornerSize) {
this.fill = fill;
this.lineSize = lineSize;
this.cornerSize = cornerSize;
stroke = new BasicStroke(lineSize);
}
public RoundedLineBorder(Paint fill, int lineSize, int cornerSize, boolean antiAlias) {
this.fill = fill;
this.lineSize = lineSize;
this.cornerSize = cornerSize;
stroke = new BasicStroke(lineSize);
aaHint = antiAlias? RenderingHints.VALUE_ANTIALIAS_ON: RenderingHints.VALUE_ANTIALIAS_OFF;
}
@Override
public Insets getBorderInsets(Component c, Insets insets) {
int size = Math.max(lineSize, cornerSize);
if(insets == null) insets = new Insets(size, size, size, size);
else insets.left = insets.top = insets.right = insets.bottom = size;
return insets;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D)g;
Paint oldPaint = g2d.getPaint();
Stroke oldStroke = g2d.getStroke();
Object oldAA = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
try {
g2d.setPaint(fill!=null? fill: c.getForeground());
g2d.setStroke(stroke);
if(aaHint != null) g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, aaHint);
int off = lineSize >> 1;
g2d.drawRoundRect(x+off, y+off, width-lineSize, height-lineSize, cornerSize, cornerSize);
}
finally {
g2d.setPaint(oldPaint);
g2d.setStroke(oldStroke);
if(aaHint != null) g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAA);
}
}
}
现在,当我更改线路时
b.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));
在你的例子中
b.setBorder(new RoundedLineBorder(Color.BLACK, 1, 10, true));
我明白了