原文: https://zetcode.com/gfx/java2d/shapesandfills/

在 Java 2D 教程的这一部分中,我们创建一些基本的和更高级的形状。 我们用纯色,渐变和纹理填充形状。

基本形状

首先,我们绘制一些基本的 Java 2D 形状。

BasicShapes.java

  1. package com.zetcode;
  2. import java.awt.Color;
  3. import java.awt.EventQueue;
  4. import java.awt.Graphics;
  5. import java.awt.Graphics2D;
  6. import java.awt.RenderingHints;
  7. import java.awt.geom.Ellipse2D;
  8. import javax.swing.JFrame;
  9. import javax.swing.JPanel;
  10. class Surface extends JPanel {
  11. private void doDrawing(Graphics g) {
  12. Graphics2D g2d = (Graphics2D) g;
  13. g2d.setPaint(new Color(150, 150, 150));
  14. RenderingHints rh = new RenderingHints(
  15. RenderingHints.KEY_ANTIALIASING,
  16. RenderingHints.VALUE_ANTIALIAS_ON);
  17. rh.put(RenderingHints.KEY_RENDERING,
  18. RenderingHints.VALUE_RENDER_QUALITY);
  19. g2d.setRenderingHints(rh);
  20. g2d.fillRect(30, 20, 50, 50);
  21. g2d.fillRect(120, 20, 90, 60);
  22. g2d.fillRoundRect(250, 20, 70, 60, 25, 25);
  23. g2d.fill(new Ellipse2D.Double(10, 100, 80, 100));
  24. g2d.fillArc(120, 130, 110, 100, 5, 150);
  25. g2d.fillOval(270, 130, 50, 50);
  26. }
  27. @Override
  28. public void paintComponent(Graphics g) {
  29. super.paintComponent(g);
  30. doDrawing(g);
  31. }
  32. }
  33. public class BasicShapesEx extends JFrame {
  34. public BasicShapesEx() {
  35. initUI();
  36. }
  37. private void initUI() {
  38. add(new Surface());
  39. setTitle("Basic shapes");
  40. setSize(350, 250);
  41. setLocationRelativeTo(null);
  42. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  43. }
  44. public static void main(String[] args) {
  45. EventQueue.invokeLater(new Runnable() {
  46. @Override
  47. public void run() {
  48. BasicShapesEx ex = new BasicShapesEx();
  49. ex.setVisible(true);
  50. }
  51. });
  52. }
  53. }

在此示例中,我们在面板上绘制了六个基本形状:正方形,矩形,圆角矩形,椭圆形,弧形和圆形。

  1. g2d.setPaint(new Color(150, 150, 150));

形状将以灰色背景绘制。

  1. g2d.fillRect(20, 20, 50, 50);
  2. g2d.fillRect(120, 20, 90, 60);

fillRect()方法用于绘制矩形和正方形。 前两个参数是要绘制的形状的 x,y 坐标。 最后两个参数是形状的宽度和高度。

  1. g2d.fillRoundRect(250, 20, 70, 60, 25, 25);

在这里,我们创建一个圆角矩形。 最后两个参数是四个角处圆弧的水平和垂直直径。

  1. g2d.fill(new Ellipse2D.Double(10, 100, 80, 100));

fill()方法绘制给定形状的内部-椭圆。

  1. g2d.fillArc(120, 130, 110, 100, 5, 150);

fillArc()方法填充覆盖指定矩形的圆弧或椭圆弧。 圆弧是圆的圆周的一部分。

  1. g2d.fillOval(270, 130, 50, 50);

使用fillOval()方法绘制一个圆。

形状和填充 - 图1

图:基本形状

一般路径

可以使用GeneralPath构造更复杂的形状。 它代表由直线,二次贝塞尔曲线和三次贝塞尔曲线构成的几何路径。

下面的示例使用此类创建星形。

StarEx.java

  1. package com.zetcode;
  2. import java.awt.Color;
  3. import java.awt.EventQueue;
  4. import java.awt.Graphics;
  5. import java.awt.Graphics2D;
  6. import java.awt.RenderingHints;
  7. import java.awt.geom.GeneralPath;
  8. import javax.swing.JFrame;
  9. import javax.swing.JPanel;
  10. class Surface extends JPanel {
  11. private final double points[][] = {
  12. { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 },
  13. { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 },
  14. { 40, 190 }, { 50, 125 }, { 0, 85 }
  15. };
  16. private void doDrawing(Graphics g) {
  17. Graphics2D g2d = (Graphics2D) g.create();
  18. g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
  19. RenderingHints.VALUE_ANTIALIAS_ON);
  20. g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
  21. RenderingHints.VALUE_RENDER_QUALITY);
  22. g2d.setPaint(Color.gray);
  23. g2d.translate(25, 5);
  24. GeneralPath star = new GeneralPath();
  25. star.moveTo(points[0][0], points[0][1]);
  26. for (int k = 1; k < points.length; k++)
  27. star.lineTo(points[k][0], points[k][1]);
  28. star.closePath();
  29. g2d.fill(star);
  30. g2d.dispose();
  31. }
  32. @Override
  33. public void paintComponent(Graphics g) {
  34. super.paintComponent(g);
  35. doDrawing(g);
  36. }
  37. }
  38. public class StarEx extends JFrame {
  39. public StarEx() {
  40. initUI();
  41. }
  42. private void initUI() {
  43. add(new Surface());
  44. setTitle("Star");
  45. setSize(350, 250);
  46. setLocationRelativeTo(null);
  47. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  48. }
  49. public static void main(String[] args) {
  50. EventQueue.invokeLater(new Runnable() {
  51. @Override
  52. public void run() {
  53. StarEx ex = new StarEx();
  54. ex.setVisible(true);
  55. }
  56. });
  57. }
  58. }

我们从一系列角度创造一颗星星。

  1. private final double points[][] = {
  2. { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 },
  3. { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 },
  4. { 40, 190 }, { 50, 125 }, { 0, 85 }
  5. };

这些是星星的坐标。

  1. GeneralPath star = new GeneralPath();

在这里,我们实例化了GeneralPath类。

  1. star.moveTo(points[0][0], points[0][1]);

我们移到GeneralPath的初始坐标。

  1. for (int k = 1; k < points.length; k++)
  2. star.lineTo(points[k][0], points[k][1]);

在这里,我们连接星的所有坐标。

  1. star.closePath();
  2. g2d.fill(star);

我们封闭路径并填充星星内部。

形状和填充 - 图2

图:星星

区域

创建复杂形状的另一种方法是组成区域。 Area存储和操纵二维空间的封闭区域的与分辨率无关的描述。 可以通过加,减,交,异或运算来操纵它。

AreasEx.java

  1. package com.zetcode;
  2. import java.awt.Color;
  3. import java.awt.EventQueue;
  4. import java.awt.Graphics;
  5. import java.awt.Graphics2D;
  6. import java.awt.RenderingHints;
  7. import java.awt.geom.Area;
  8. import java.awt.geom.Ellipse2D;
  9. import java.awt.geom.Rectangle2D;
  10. import javax.swing.JFrame;
  11. import javax.swing.JPanel;
  12. class Surface extends JPanel {
  13. public void doDrawing(Graphics g) {
  14. Graphics2D g2d = (Graphics2D) g;
  15. RenderingHints rh = new RenderingHints(
  16. RenderingHints.KEY_ANTIALIASING,
  17. RenderingHints.VALUE_ANTIALIAS_ON);
  18. rh.put(RenderingHints.KEY_RENDERING,
  19. RenderingHints.VALUE_RENDER_QUALITY);
  20. g2d.setRenderingHints(rh);
  21. g2d.setPaint(Color.gray);
  22. Area a1 = new Area(new Rectangle2D.Double(20, 20, 100, 100));
  23. Area a2 = new Area(new Ellipse2D.Double(50, 50, 100, 100));
  24. a1.subtract(a2);
  25. g2d.fill(a1);
  26. Area a3 = new Area(new Rectangle2D.Double(150, 20, 100, 100));
  27. Area a4 = new Area(new Ellipse2D.Double(150, 20, 100, 100));
  28. a3.subtract(a4);
  29. g2d.fill(a3);
  30. Area a5 = new Area(new Rectangle2D.Double(280, 20, 100, 100));
  31. Area a6 = new Area(new Ellipse2D.Double(320, 40, 100, 100));
  32. a5.add(a6);
  33. g2d.fill(a5);
  34. }
  35. @Override
  36. public void paintComponent(Graphics g) {
  37. super.paintComponent(g);
  38. doDrawing(g);
  39. }
  40. }
  41. public class AreasEx extends JFrame {
  42. public AreasEx() {
  43. initUI();
  44. }
  45. private void initUI() {
  46. add(new Surface());
  47. setTitle("Areas");
  48. setSize(450, 200);
  49. setLocationRelativeTo(null);
  50. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  51. }
  52. public static void main(String[] args) {
  53. EventQueue.invokeLater(new Runnable() {
  54. @Override
  55. public void run() {
  56. AreasEx ex = new AreasEx();
  57. ex.setVisible(true);
  58. }
  59. });
  60. }
  61. }

该示例通过操纵区域来创建三种不同的形状。

  1. Area a1 = new Area(new Rectangle2D.Double(20, 20, 100, 100));
  2. Area a2 = new Area(new Ellipse2D.Double(50, 50, 100, 100));
  3. a1.subtract(a2);
  4. g2d.fill(a1);

此代码通过从矩形中减去椭圆来构造形状。

  1. Area a5 = new Area(new Rectangle2D.Double(280, 20, 100, 100));
  2. Area a6 = new Area(new Ellipse2D.Double(320, 40, 100, 100));
  3. a5.add(a6);
  4. g2d.fill(a5);

这些线通过在椭圆上添加矩形来构造形状。

形状和填充 - 图3

图:区域

色彩

Color类用于处理 Java 2D 中的颜色。 要使用当前颜色填充矩形,我们使用fillRect()方法。

ColoursEx.java

  1. package com.zetcode;
  2. import java.awt.Color;
  3. import java.awt.EventQueue;
  4. import java.awt.Graphics;
  5. import java.awt.Graphics2D;
  6. import javax.swing.JFrame;
  7. import javax.swing.JPanel;
  8. class Surface extends JPanel {
  9. public void doDrawing(Graphics g) {
  10. Graphics2D g2d = (Graphics2D) g;
  11. g2d.setColor(new Color(125, 167, 116));
  12. g2d.fillRect(10, 10, 90, 60);
  13. g2d.setColor(new Color(42, 179, 231));
  14. g2d.fillRect(130, 10, 90, 60);
  15. g2d.setColor(new Color(70, 67, 123));
  16. g2d.fillRect(250, 10, 90, 60);
  17. g2d.setColor(new Color(130, 100, 84));
  18. g2d.fillRect(10, 100, 90, 60);
  19. g2d.setColor(new Color(252, 211, 61));
  20. g2d.fillRect(130, 100, 90, 60);
  21. g2d.setColor(new Color(241, 98, 69));
  22. g2d.fillRect(250, 100, 90, 60);
  23. g2d.setColor(new Color(217, 146, 54));
  24. g2d.fillRect(10, 190, 90, 60);
  25. g2d.setColor(new Color(63, 121, 186));
  26. g2d.fillRect(130, 190, 90, 60);
  27. g2d.setColor(new Color(31, 21, 1));
  28. g2d.fillRect(250, 190, 90, 60);
  29. }
  30. @Override
  31. public void paintComponent(Graphics g) {
  32. super.paintComponent(g);
  33. doDrawing(g);
  34. }
  35. }
  36. public class ColoursEx extends JFrame {
  37. public ColoursEx() {
  38. initUI();
  39. }
  40. private void initUI() {
  41. add(new Surface());
  42. setTitle("Colours");
  43. setSize(360, 300);
  44. setLocationRelativeTo(null);
  45. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  46. }
  47. public static void main(String[] args) {
  48. EventQueue.invokeLater(new Runnable() {
  49. @Override
  50. public void run() {
  51. ColoursEx ex = new ColoursEx();
  52. ex.setVisible(true);
  53. }
  54. });
  55. }
  56. }

在示例中,我们绘制了九个彩色矩形。

  1. Graphics2D g2d = (Graphics2D) g;

更改图形上下文的color属性时,无需创建Graphics2D类的副本或重置该值。

  1. g2d.setColor(new Color(125, 167, 116));

使用Color类创建新的颜色。 构造器的参数是新颜色的红色,绿色和蓝色部分。 setColor()方法将图形上下文的当前颜色设置为指定的颜色值。 所有后续图形操作均使用此颜色值。

  1. g2d.fillRect(10, 15, 90, 60);

为了用颜色填充矩形,我们使用fillRect()方法。

形状和填充 - 图4

图:颜色

渐变

在计算机图形学中,渐变是从浅到深或从一种颜色到另一种颜色的阴影的平滑混合。 在 2D 绘图程序和绘画程序中,渐变用于创建彩色背景和特殊效果以及模拟灯光和阴影。 (answers.com)

GradientsEx.java

  1. package com.zetcode;
  2. import java.awt.Color;
  3. import java.awt.EventQueue;
  4. import java.awt.GradientPaint;
  5. import java.awt.Graphics;
  6. import java.awt.Graphics2D;
  7. import javax.swing.JFrame;
  8. import javax.swing.JPanel;
  9. class Surface extends JPanel {
  10. private void doDrawing(Graphics g) {
  11. Graphics2D g2d = (Graphics2D) g.create();
  12. GradientPaint gp1 = new GradientPaint(5, 5,
  13. Color.red, 20, 20, Color.black, true);
  14. g2d.setPaint(gp1);
  15. g2d.fillRect(20, 20, 300, 40);
  16. GradientPaint gp2 = new GradientPaint(5, 25,
  17. Color.yellow, 20, 2, Color.black, true);
  18. g2d.setPaint(gp2);
  19. g2d.fillRect(20, 80, 300, 40);
  20. GradientPaint gp3 = new GradientPaint(5, 25,
  21. Color.green, 2, 2, Color.black, true);
  22. g2d.setPaint(gp3);
  23. g2d.fillRect(20, 140, 300, 40);
  24. GradientPaint gp4 = new GradientPaint(25, 25,
  25. Color.blue, 15, 25, Color.black, true);
  26. g2d.setPaint(gp4);
  27. g2d.fillRect(20, 200, 300, 40);
  28. GradientPaint gp5 = new GradientPaint(0, 0,
  29. Color.orange, 0, 20, Color.black, true);
  30. g2d.setPaint(gp5);
  31. g2d.fillRect(20, 260, 300, 40);
  32. g2d.dispose();
  33. }
  34. @Override
  35. public void paintComponent(Graphics g) {
  36. super.paintComponent(g);
  37. doDrawing(g);
  38. }
  39. }
  40. public class GradientsEx extends JFrame {
  41. public GradientsEx() {
  42. initUI();
  43. }
  44. private void initUI() {
  45. add(new Surface());
  46. setTitle("Gradients");
  47. setSize(350, 350);
  48. setLocationRelativeTo(null);
  49. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  50. }
  51. public static void main(String[] args) {
  52. EventQueue.invokeLater(new Runnable() {
  53. @Override
  54. public void run() {
  55. GradientsEx ex = new GradientsEx();
  56. ex.setVisible(true);
  57. }
  58. });
  59. }
  60. }

我们的代码示例展示了五个带有渐变的矩形。

  1. GradientPaint gp4 = new GradientPaint(25, 25,
  2. Color.blue, 15, 25, Color.black, true);

要使用渐变,我们使用GradientPaint类。 通过操纵颜色值以及起点和终点,我们可以获得不同的结果。

  1. g2d.setPaint(gp4);

通过调用setPaint()方法激活渐变。

形状和填充 - 图5

图:渐变

纹理

纹理是应用于形状的位图图像。 要在 Java 2D 中使用纹理,我们使用TexturePaint类。 通过setPaint()方法应用纹理。

TexturesEx.java

  1. package com.zetcode;
  2. import java.awt.EventQueue;
  3. import java.awt.Graphics;
  4. import java.awt.Graphics2D;
  5. import java.awt.Rectangle;
  6. import java.awt.TexturePaint;
  7. import java.awt.image.BufferedImage;
  8. import java.io.File;
  9. import java.io.IOException;
  10. import java.util.logging.Level;
  11. import java.util.logging.Logger;
  12. import javax.imageio.ImageIO;
  13. import javax.swing.JFrame;
  14. import javax.swing.JPanel;
  15. class Surface extends JPanel {
  16. private BufferedImage slate;
  17. private BufferedImage java;
  18. private BufferedImage pane;
  19. private TexturePaint slatetp;
  20. private TexturePaint javatp;
  21. private TexturePaint panetp;
  22. public Surface() {
  23. loadImages();
  24. }
  25. private void loadImages() {
  26. try {
  27. slate = ImageIO.read(new File("slate.png"));
  28. java = ImageIO.read(new File("java.png"));
  29. pane = ImageIO.read(new File("pane.png"));
  30. } catch (IOException ex) {
  31. Logger.getLogger(Surface.class.getName()).log(
  32. Level.SEVERE, null, ex);
  33. }
  34. }
  35. private void doDrawing(Graphics g) {
  36. Graphics2D g2d = (Graphics2D) g.create();
  37. slatetp = new TexturePaint(slate, new Rectangle(0, 0, 90, 60));
  38. javatp = new TexturePaint(java, new Rectangle(0, 0, 90, 60));
  39. panetp = new TexturePaint(pane, new Rectangle(0, 0, 90, 60));
  40. g2d.setPaint(slatetp);
  41. g2d.fillRect(10, 15, 90, 60);
  42. g2d.setPaint(javatp);
  43. g2d.fillRect(130, 15, 90, 60);
  44. g2d.setPaint(panetp);
  45. g2d.fillRect(250, 15, 90, 60);
  46. g2d.dispose();
  47. }
  48. @Override
  49. public void paintComponent(Graphics g) {
  50. super.paintComponent(g);
  51. doDrawing(g);
  52. }
  53. }
  54. public class TexturesEx extends JFrame {
  55. public TexturesEx() {
  56. initUI();
  57. }
  58. private void initUI() {
  59. add(new Surface());
  60. setTitle("Textures");
  61. setSize(360, 120);
  62. setLocationRelativeTo(null);
  63. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  64. }
  65. public static void main(String[] args) {
  66. EventQueue.invokeLater(new Runnable() {
  67. @Override
  68. public void run() {
  69. TexturesEx ex = new TexturesEx();
  70. ex.setVisible(true);
  71. }
  72. });
  73. }
  74. }

在代码示例中,我们用三个不同的纹理填充三个矩形。

  1. slate = ImageIO.read(new File("slate.png"));

使用ImageIO类,我们将图像读取到缓冲图像中。

  1. slatetp = new TexturePaint(slate, new Rectangle(0, 0, 90, 60));

我们从缓冲图像中创建一个TexturePaint类。

  1. g2d.setPaint(slatetp);
  2. g2d.fillRect(10, 15, 90, 60);

我们用纹理填充矩形。

形状和填充 - 图6

图:纹理

在 Java 2D 教程的这一部分中,我们介绍了 Java 2D 库的一些基本形状和更高级的形状。