绘制具有给定厚度、位置和半径的环。 (Java2D)

Draw ring with given thickness, position, and radius. (Java2D)

我需要画一个给定厚度的环,看起来像这样:

中心必须是透明的,这样它就不会覆盖之前绘制的形状。 (或其他戒指)我试过这样的事情:

//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);

其中画出一个满意的圆环,但覆盖了其他形状;内部是白色的,不透明。我怎样才能 modify/rewrite 我的代码不这样做?

您可以为此使用 graphics.setStroke(...)。这样中心将完全透明,因此不会覆盖以前绘制的形状。在我的例子中,由于这种方法,我不得不做一些额外的计算,以确保显示的 xy 坐标实际上与 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;
    }

}

您可以使用 ShapeArea 类 来创建有趣的效果:

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();
            }
        });
*/
    }
}

使用区域,您还可以将多个形状相加或获取多个形状的交集。

你可以创建一个Area from an Ellipse2D that describes the outer circle, and subtract the ellipse that describes the inner circle. This way, you will obtain an actual Shape that can either be drawn or filled(这只会指环实际覆盖的区域!)。

优点是您真正拥有戒指的几何形状。例如,这允许您检查环形 contains a certain point, or to fill it with a 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;
    }

}