将多个 graphic2d 组件绘制到 JPanel 中

Drawing multiple graphic2d components into JPanel

我已经阅读了很多关于绘制 Graphics2D 组件并添加到 JPanel/JFrame 的教程,但我找不到如何简单地将多个这些组件添加到一个 JPanel 中。我下面的代码只添加了 1 个组件(行),我找不到为什么不能添加更多组件。

我做错了什么?

期望的行为:应该有 3 条红线。

我的全部代码:

package Examples;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Example1 extends JFrame {

    private final JPanel panel;

    public Example1() {

        // jpanel with graphics
        panel = new JPanel();
        panel.setPreferredSize(new Dimension(200, 200));
        panel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        panel.setBackground(Color.WHITE);
        add(panel);


        // adding lines to jpanel
        AddMyLine(); // 1st: this works well
        AddMyLine(); // 2nd: this doesn't work
        AddMyLine(); // 3rd: this doesn't work


        setLayout(new FlowLayout(FlowLayout.LEFT));
        setSize(250, 250);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        setLocationRelativeTo(null);
    }


    // add new line to jpanel
    private void AddMyLine() {
        MyLine c = new MyLine();
        System.out.println(c);
        panel.add(c);
    }



    // line component
    private class MyLine extends JComponent {

        public MyLine() {
            setPreferredSize(new Dimension(200, 200));
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D)g;
            g2d.setColor(Color.red);
            g2d.setStroke(new BasicStroke(1));
            int x1 = (int)Math.round(Math.random()*200);
            int y1 = (int)Math.round(Math.random()*200);
            int x2 = (int)Math.round(Math.random()*200);
            int y2 = (int)Math.round(Math.random()*200);
            g2d.drawLine(x1,y1,x2,y2);
        }
    }


    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Example1();
            }
        });     

    }
}

您的 MyLine class 不应是 Swing 组件,因此不应扩展 JComponent。相反,它应该是一个逻辑实体,实际上可以是实现 Shape 的东西,例如 Line2D,或者可以是您自己的完整 class,但应该知道如何绘制自己,即,如果它不实现 Shape ,那么它应该有其他 classes 可以调用的某种类型的 draw(Graphics2D g) 方法。相反,我认为您应该致力于扩展面板的 JPanel class,这样您就可以覆盖它的 paintComponent 方法,给它一个集合来保存添加到其中的任何 MyLine 项目,并在 paintComponent 中绘制 MyLine 项目.

其他选项包括直接在 BufferedImage 上绘图,然后在 JPanel 的 paintComponent 方法中显示该 BufferedImage。这对静态图像非常有用,但不适合需要更改或移动的图像。

例如

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;

public class DrawChit extends JPanel {
   private static final int PREF_W = 500;
   private static final int PREF_H = PREF_W;
   private List<Shape> shapes = new ArrayList<>();

   public DrawChit() {
      setBackground(Color.white);
   }

   public void addShape(Shape shape) {
      shapes.add(shape);
      repaint();
   }

   @Override // make it bigger
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      for (Shape shape : shapes) {
         g2.draw(shape);
      }
   }

   private static void createAndShowGui() {
      DrawChit drawChit = new DrawChit();

      drawChit.addShape(new Line2D.Double(10, 10, 100, 100));
      drawChit.addShape(new Ellipse2D.Double(120, 120, 200, 200));

      JFrame frame = new JFrame("DrawChit");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(drawChit);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

或者使用我自己的 MyDrawable class 的示例,生成如下所示的 GUI:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

@SuppressWarnings("serial")
public class DrawChit extends JPanel {
   private static final int PREF_W = 600;
   private static final int PREF_H = PREF_W;
   private List<MyDrawable> drawables = new ArrayList<>();

   public DrawChit() {
      setBackground(Color.white);
   }

   public void addMyDrawable(MyDrawable myDrawable) {
      drawables.add(myDrawable);
      repaint();
   }

   @Override
   // make it bigger
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      for (MyDrawable myDrawable : drawables) {
         myDrawable.draw(g2);
      }
   }

   public void clearAll() {
      drawables.clear();
      repaint();
   }

   private static void createAndShowGui() {
      final List<MyDrawable> myDrawables = new ArrayList<>();
      myDrawables.add(new MyDrawable(new Line2D.Double(100, 40, 400, 400),
            Color.red, new BasicStroke(40)));
      myDrawables.add(new MyDrawable(new Ellipse2D.Double(50, 10, 400, 400),
            Color.blue, new BasicStroke(18)));
      myDrawables.add(new MyDrawable(new Rectangle2D.Double(40, 200, 300, 300),
            Color.cyan, new BasicStroke(25)));
      myDrawables.add(new MyDrawable(new RoundRectangle2D.Double(75, 75, 490, 450, 40, 40),
            Color.green, new BasicStroke(12)));

      final DrawChit drawChit = new DrawChit();

      JFrame frame = new JFrame("DrawChit");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(drawChit);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);

      int timerDelay = 1000;
      new Timer(timerDelay, new ActionListener() {
         private int drawCount = 0;

         @Override
         public void actionPerformed(ActionEvent e) {
            if (drawCount >= myDrawables.size()) {
               drawCount = 0;
               drawChit.clearAll();
            } else {
               drawChit.addMyDrawable(myDrawables.get(drawCount));
               drawCount++;
            }
         }
      }).start();
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class MyDrawable {
   private Shape shape;
   private Color color;
   private Stroke stroke;

   public MyDrawable(Shape shape, Color color, Stroke stroke) {
      this.shape = shape;
      this.color = color;
      this.stroke = stroke;
   }

   public Shape getShape() {
      return shape;
   }

   public Color getColor() {
      return color;
   }

   public Stroke getStroke() {
      return stroke;
   }

   public void draw(Graphics2D g2) {
      Color oldColor = g2.getColor();
      Stroke oldStroke = g2.getStroke();

      g2.setColor(color);
      g2.setStroke(stroke);
      g2.draw(shape);

      g2.setColor(oldColor);
      g2.setStroke(oldStroke);
   }

   public void fill(Graphics2D g2) {
      Color oldColor = g2.getColor();
      Stroke oldStroke = g2.getStroke();

      g2.setColor(color);
      g2.setStroke(stroke);
      g2.fill(shape);

      g2.setColor(oldColor);
      g2.setStroke(oldStroke);
   }

}

您不应该通过添加组件来画线。组件是面板、按钮等。

请参阅本教程,了解如何使用 Graphics2D 进行绘图:https://docs.oracle.com/javase/tutorial/2d/geometry/primitives.html

您的代码添加了三个组件,但面板不够大,无法显示其他两个组件

    panel.setPreferredSize(new Dimension(200, 600));
    setSize(250, 800);