绘制具有给定厚度、位置和半径的环。 (Java2D)
Posted
技术标签:
【中文标题】绘制具有给定厚度、位置和半径的环。 (Java2D)【英文标题】:Draw ring with given thickness, position, and radius. (Java2D) 【发布时间】:2016-06-02 03:40:17 【问题描述】:我需要画一个给定厚度的环,看起来像这样:
中心必须是透明的,这样它就不会覆盖之前绘制的形状。 (或其他戒指)我尝试过这样的事情:
//g is a Graphics2D object
g.setColor(Color.RED);
g.drawOval(x,y,width,height);
g.setColor(Color.WHITE);
g.drawOval(x+thickness,y+thickness,width-2*thickness,height-2*thickness);
它绘制了一个令人满意的环,但它覆盖了其他形状;内部是白色的,不透明。我怎样才能修改/重写我的代码,使它不会那样做?
【问题讨论】:
【参考方案1】:您可以从描述外圆的Ellipse2D
和描述内圆的椭圆subtract
创建一个Area
。这样,您将获得一个实际的Shape
,它可以是drawn 或filled(这只是指环实际覆盖的区域!)。
优点是您确实拥有戒指的几何形状。例如,这使您可以检查环形contains
是否为某个点,或者用不止一种颜色的Paint
填充它:
这里是一个例子,相关部分是createRingShape
方法:
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RingPaintTest
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
@Override
public void run()
createAndShowGUI();
);
private static void createAndShowGUI()
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
RingPaintTestPanel p = new RingPaintTestPanel();
f.getContentPane().add(p);
f.setSize(800,800);
f.setLocationRelativeTo(null);
f.setVisible(true);
class RingPaintTestPanel extends JPanel
@Override
protected void paintComponent(Graphics gr)
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.RED);
g.drawString("Text", 100, 100);
g.drawString("Text", 300, 100);
Shape ring = createRingShape(100, 100, 80, 20);
g.setColor(Color.CYAN);
g.fill(ring);
g.setColor(Color.BLACK);
g.draw(ring);
Shape otherRing = createRingShape(300, 100, 80, 20);
g.setPaint(new GradientPaint(
new Point(250, 40), Color.RED,
new Point(350, 200), Color.GREEN));
g.fill(otherRing);
g.setColor(Color.BLACK);
g.draw(otherRing);
private static Shape createRingShape(
double centerX, double centerY, double outerRadius, double thickness)
Ellipse2D outer = new Ellipse2D.Double(
centerX - outerRadius,
centerY - outerRadius,
outerRadius + outerRadius,
outerRadius + outerRadius);
Ellipse2D inner = new Ellipse2D.Double(
centerX - outerRadius + thickness,
centerY - outerRadius + thickness,
outerRadius + outerRadius - thickness - thickness,
outerRadius + outerRadius - thickness - thickness);
Area area = new Area(outer);
area.subtract(new Area(inner));
return area;
【讨论】:
(1+) @Marco13,添加渐变示例需要额外的时间:)【参考方案2】:您可以使用Shape
和Area
类来创建有趣的效果:
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
import java.net.*;
public class Subtract extends JPanel
@Override
protected void paintComponent(Graphics g)
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int size = 100;
int thickness = 10;
int innerSize = size - (2 * thickness);
Shape outer = new Ellipse2D.Double(0, 0, size, size);
Shape inner = new Ellipse2D.Double(thickness, thickness, innerSize, innerSize);
Area circle = new Area( outer );
circle.subtract( new Area(inner) );
int x = (getSize().width - size) / 2;
int y = (getSize().height - size) / 2;
g2d.translate(x, y);
g2d.setColor(Color.CYAN);
g2d.fill(circle);
g2d.setColor(Color.BLACK);
g2d.draw(circle);
g2d.dispose();
private static void createAndShowGUI()
JFrame frame = new JFrame("Subtract");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Subtract());
frame.setLocationByPlatform( true );
frame.setSize(200, 200);
frame.setVisible( true );
public static void main(String[] args)
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
public void run()
createAndShowGUI();
);
*/
使用一个区域,您还可以将多个形状添加在一起或获得多个形状的交集。
【讨论】:
所以,再一次,我太慢了... :-/【参考方案3】:您可以为此使用graphics.setStroke(...)
。这样,中心将是完全透明的,因此不会覆盖以前绘制的形状。在我的示例中,由于这种方法,我必须进行一些额外的计算,以确保显示的 x
和 y
坐标实际上与 Ring
实例的坐标相同:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example
public Example()
ArrayList<Ring> rings = new ArrayList<Ring>();
rings.add(new Ring(10, 10, 100, 20, Color.CYAN));
JPanel panel = new JPanel()
@Override
public void paintComponent(Graphics g)
super.paintComponent(g);
Graphics2D gg = (Graphics2D) g.create();
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Ring ring : rings)
// Previously drawn
gg.setColor(Color.BLACK);
String str = "Hello!";
gg.drawString(str, ring.getX() + (ring.getWidth() - gg.getFontMetrics().stringWidth(str)) / 2,
ring.getY() + ring.getHeight() / 2 + gg.getFontMetrics().getAscent());
// The actual ring
ring.draw(gg);
gg.dispose();
;
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
public static void main(String[] args)
EventQueue.invokeLater(new Runnable()
@Override
public void run()
new Example();
);
class Ring
private int x, y, width, height, thickness;
private Color color;
public Ring(int x, int y, int width, int height, int thickness, Color color)
setX(x);
setY(y);
setWidth(width);
setHeight(height);
setThickness(thickness);
setColor(color);
public Ring(int x, int y, int radius, int thickness, Color color)
this(x, y, radius * 2, radius * 2, thickness, color);
public void draw(Graphics2D gg)
Stroke oldStroke = gg.getStroke();
Color oldColor = gg.getColor();
gg.setColor(Color.BLACK);
gg.setStroke(new BasicStroke(getThickness()));
gg.drawOval(getX() + getThickness() / 2, getY() + getThickness() / 2, getWidth() - getThickness(),
getHeight() - getThickness());
gg.setColor(getColor());
gg.setStroke(new BasicStroke(getThickness() - 2));
gg.drawOval(getX() + getThickness() / 2, getY() + getThickness() / 2, getWidth() - getThickness(),
getHeight() - getThickness());
gg.setStroke(oldStroke);
gg.setColor(oldColor);
public int getX()
return x;
public void setX(int x)
this.x = x;
public int getY()
return y;
public void setY(int y)
this.y = y;
public int getWidth()
return width;
public void setWidth(int width)
this.width = width;
public int getHeight()
return height;
public void setHeight(int height)
this.height = height;
public int getThickness()
return thickness;
public void setThickness(int thickness)
this.thickness = thickness;
public Color getColor()
return color;
public void setColor(Color color)
this.color = color;
【讨论】:
以上是关于绘制具有给定厚度、位置和半径的环。 (Java2D)的主要内容,如果未能解决你的问题,请参考以下文章
使用java程序查找具有指定半径的给定纬度和经度(即位置)的周围纬度和纬度值