如何在周围没有 "invisible box" 的情况下绘制自定义圆形 JComponent?
How can I paint a custom circular JComponent without an "invisible box" around it?
我正在编写一个 JApplet,该 JApplet 显示一个图表,其中数字在圆圈中,线条连接圆圈。我创建了一个 class 来扩展 JComponent 以充当圆圈。我重写了 paintComponent() 方法来绘制一个内部带有数字的圆圈,并将这些圆圈放在我的小程序上,然后我在 paint() 方法中绘制了线条。
但是,如果线条以一定角度碰到圆圈,它们会在圆圈之前在勾勒出整个 JComponent 轮廓的正方形处提前切出,即使背景应该是透明的。这在圆圈周围形成了一个 "invisible box"。
我准备了一个小程序来演示这个问题:
下面是该示例的代码:
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.*;
public class Circle extends JApplet {
private static final long serialVersionUID = 1L;
myCircle myC = new myCircle(10, 215, 215); // custom circle
Container c;
public void init() {
setSize(500, 500);
c = getContentPane();
c.setLayout(null);
c.setBackground(Color.lightGray);
c.add(myC);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.black);
g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
//draw lines
g2d.draw(new Line2D.Double(0f, 0f, 500f, 500f));
g2d.draw(new Line2D.Double(0f, 500f, 500f, 0f));
g2d.draw(new Line2D.Double(0f, 250f, 500f, 250f));
g2d.draw(new Line2D.Double(250f, 0f, 250f, 500f));
g2d.draw(new Line2D.Double(150f, 0f, 350f, 500f));
myC.repaint(); // put the circle on top
}
public class myCircle extends JComponent {
private static final long serialVersionUID = 1L;
int number; // number to display
public myCircle(int num, int x, int y) {
this.number = num;
this.setLocation(x, y);
this.setSize(75, 75);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
g2d.setColor(Color.white);
g2d.fill(new Ellipse2D.Float(1f, 1f, 70f, 70f));
g2d.setColor(Color.black);
g2d.draw(new Ellipse2D.Float(1f, 1f, 70f, 70f));
g2d.drawString(Integer.toString(number), 15f, 20f);
}
}
}
您需要查看所绘制线条的长度。从图形的边缘到圆圈的角度比侧面更长。回想一下具有 45 度、45 度和 90 度角的三角形,边长之比为 1:1:sqrt(2)
我不会单独使用组件来表示圆形。相反,只需将其全部绘制在一个 JPanel
上(我使用的是 JFrame
而不是小程序):
public class Circle extends JPanel {
int number = 10;
float size = 500f;
float rad = 70f;
float stringLocX = 15f, stringLocy = 20f;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.LIGHT_GRAY);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
g2d.setColor(Color.BLACK);
g2d.draw(new Line2D.Double(0f, 0f, size, size));
g2d.draw(new Line2D.Double(0f, size, size, 0f));
g2d.draw(new Line2D.Double(0f, size / 2, size, size / 2));
g2d.draw(new Line2D.Double(size / 2, 0f, size / 2, size));
g2d.draw(new Line2D.Double(150f, 0f, 350f, 500f));
Ellipse2D.Float circle = new Ellipse2D.Float((size - rad) / 2, (size - rad) / 2, rad, rad);
g2d.setColor(Color.WHITE);
g2d.fill(circle);
g2d.setColor(Color.BLACK);
g2d.draw(circle);
g2d.drawString(Integer.toString(number), (size - rad) / 2 + stringLocX,
(size - rad) / 2 + stringLocy);
}
@Override
public Dimension getPreferredSize() {
return new Dimension((int) size, (int) size);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.add(new Circle());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
});
}
}
根据您拥有的圆圈数量以及它们必须包含的数据,您可以只保留这些数字的列表,然后在 painComponent
中遍历该列表并绘制它们。
备注:
- 不要使用
null
布局。
- 最好将硬编码数字保留为字段,这样您可以更轻松地更改它们,可能使它们成为
final
.
我正在编写一个 JApplet,该 JApplet 显示一个图表,其中数字在圆圈中,线条连接圆圈。我创建了一个 class 来扩展 JComponent 以充当圆圈。我重写了 paintComponent() 方法来绘制一个内部带有数字的圆圈,并将这些圆圈放在我的小程序上,然后我在 paint() 方法中绘制了线条。
但是,如果线条以一定角度碰到圆圈,它们会在圆圈之前在勾勒出整个 JComponent 轮廓的正方形处提前切出,即使背景应该是透明的。这在圆圈周围形成了一个 "invisible box"。
我准备了一个小程序来演示这个问题:
下面是该示例的代码:
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.*;
public class Circle extends JApplet {
private static final long serialVersionUID = 1L;
myCircle myC = new myCircle(10, 215, 215); // custom circle
Container c;
public void init() {
setSize(500, 500);
c = getContentPane();
c.setLayout(null);
c.setBackground(Color.lightGray);
c.add(myC);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.black);
g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
//draw lines
g2d.draw(new Line2D.Double(0f, 0f, 500f, 500f));
g2d.draw(new Line2D.Double(0f, 500f, 500f, 0f));
g2d.draw(new Line2D.Double(0f, 250f, 500f, 250f));
g2d.draw(new Line2D.Double(250f, 0f, 250f, 500f));
g2d.draw(new Line2D.Double(150f, 0f, 350f, 500f));
myC.repaint(); // put the circle on top
}
public class myCircle extends JComponent {
private static final long serialVersionUID = 1L;
int number; // number to display
public myCircle(int num, int x, int y) {
this.number = num;
this.setLocation(x, y);
this.setSize(75, 75);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
g2d.setColor(Color.white);
g2d.fill(new Ellipse2D.Float(1f, 1f, 70f, 70f));
g2d.setColor(Color.black);
g2d.draw(new Ellipse2D.Float(1f, 1f, 70f, 70f));
g2d.drawString(Integer.toString(number), 15f, 20f);
}
}
}
您需要查看所绘制线条的长度。从图形的边缘到圆圈的角度比侧面更长。回想一下具有 45 度、45 度和 90 度角的三角形,边长之比为 1:1:sqrt(2)
我不会单独使用组件来表示圆形。相反,只需将其全部绘制在一个 JPanel
上(我使用的是 JFrame
而不是小程序):
public class Circle extends JPanel {
int number = 10;
float size = 500f;
float rad = 70f;
float stringLocX = 15f, stringLocy = 20f;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.LIGHT_GRAY);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
g2d.setColor(Color.BLACK);
g2d.draw(new Line2D.Double(0f, 0f, size, size));
g2d.draw(new Line2D.Double(0f, size, size, 0f));
g2d.draw(new Line2D.Double(0f, size / 2, size, size / 2));
g2d.draw(new Line2D.Double(size / 2, 0f, size / 2, size));
g2d.draw(new Line2D.Double(150f, 0f, 350f, 500f));
Ellipse2D.Float circle = new Ellipse2D.Float((size - rad) / 2, (size - rad) / 2, rad, rad);
g2d.setColor(Color.WHITE);
g2d.fill(circle);
g2d.setColor(Color.BLACK);
g2d.draw(circle);
g2d.drawString(Integer.toString(number), (size - rad) / 2 + stringLocX,
(size - rad) / 2 + stringLocy);
}
@Override
public Dimension getPreferredSize() {
return new Dimension((int) size, (int) size);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.add(new Circle());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
});
}
}
根据您拥有的圆圈数量以及它们必须包含的数据,您可以只保留这些数字的列表,然后在 painComponent
中遍历该列表并绘制它们。
备注:
- 不要使用
null
布局。 - 最好将硬编码数字保留为字段,这样您可以更轻松地更改它们,可能使它们成为
final
.