Java如何实现无损绘画?

How to achieve non-destructive painting in Java?

我想在面板上画出许多不同频率的正弦曲线,但是因为绘画是破坏性的,所以我无法实现。我只能看到最后绘制的正弦曲线。

在代码中,generateSinus() 方法只被调用了三次,但它可能会被调用很多次,我不想为 paintComponent( ) 方法。

有没有办法实现无损绘画,看到所有不同频率的正弦曲线?

请看下面的代码:

package testdrawsinus;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class TestDrawSinus extends JPanel 
{
   private static double[] x;
   private static double[] y;
   private static boolean buttonClicked = false;
   private static JPanel panel = new TestDrawSinus();
   
   @Override
   public void paintComponent(Graphics g) 
   {
      super.paintComponent(g);
      g.setColor(Color.GREEN);
      if (buttonClicked)
      {          
          for (int i=0; i<x.length; i++)
          {                   
             g.fillOval((int)x[i] + panel.getWidth()/2, -1*((int)y[i]) + panel.getHeight()/2, 10, 10);                          
          }
          buttonClicked = false;
      }
   }

   private static void generateSinus(int freq)
   {
      x = new double[200];
      y = new double[200];
      for (int i=0; i<=199; i++)
      {
         x[i]= (double)i;
         y[i] = 100*Math.sin(2*Math.PI*freq*i/200);
              
      }
   }

   public static void main(String[] args) 
   {
      JFrame frame = new JFrame();  
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setLayout(null);
      frame.setSize(800, 600);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);

      panel.setLayout(null);
      panel.setBounds(20,20, 700,400);
      panel.setBackground(Color.BLACK);
      frame.add(panel);

      JButton button1 = new JButton();
      button1.setText("plot");
      button1.setBounds(300, 500, 150, 50);
      frame.add(button1);

      button1.addActionListener(new ActionListener() 
      {
         @Override
         public void actionPerformed(ActionEvent e) 
         {                   
           buttonClicked = true; 
           generateSinus(1);
           panel.repaint();
           generateSinus(2);
           panel.repaint();
           generateSinus(3);
           panel.repaint();
         }
               
      });              
   }
}

感谢您的帮助。

有多种方法可以做到这一点,一种方法是将每个系列分成自己的模型,然后让面板绘制每个模型,例如...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    private Color[] masterColors = new Color[]{
        Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY,
        Color.GREEN, Color.MAGENTA, Color.ORANGE, Color.PINK,
        Color.RED, Color.WHITE, Color.YELLOW
    };

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                TestDrawSinus sinusPane = new TestDrawSinus();

                JFrame frame = new JFrame();
                frame.add(sinusPane);

                JButton button1 = new JButton();
                button1.setText("plot");
                frame.add(button1, BorderLayout.SOUTH);

                button1.addActionListener(new ActionListener() {
                    private List<Color> colors = new ArrayList<>();
                    private int freq = 0;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        sinusPane.addSinusPlot(generateSinus(++freq, nextColor()));
                        sinusPane.addSinusPlot(generateSinus(++freq, nextColor()));
                        sinusPane.addSinusPlot(generateSinus(++freq, nextColor()));
                    }

                    protected Color nextColor() {
                        if (colors.isEmpty()) {
                            colors.addAll(Arrays.asList(masterColors));
                            Collections.shuffle(colors);
                        }
                        return colors.remove(0);
                    }

                });

                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private Random rnd = new Random();

    private SinusPlot generateSinus(int freq, Color color) {
        double[] x = new double[200];
        double[] y = new double[200];
        for (int i = 0; i < 200; i++) {
            x[i] = (double) i;
            y[i] = 100 * Math.sin(2d * Math.PI * freq * i / 200d);
        }
        return new SinusPlot(x, y, color);
    }

    public class SinusPlot {
        private double[] x;
        private double[] y;
        private Color color;

        public SinusPlot(double[] x, double[] y, Color color) {
            this.x = x;
            this.y = y;
            this.color = color;
        }

        public int getSize() {
            return x.length;
        }

        public double getXAt(int index) {
            return x[index];
        }

        public double getYAt(int index) {
            return y[index];
        }

        public Color getColor() {
            return color;
        }

    }

    public class TestDrawSinus extends JPanel {
        private List<SinusPlot> plots = new ArrayList<>(8);

        public void addSinusPlot(SinusPlot plot) {
            plots.add(plot);
            repaint();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(800, 600);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            for (SinusPlot plot : plots) {
                System.out.println(plot.getColor());
                g2d.setColor(plot.getColor());
                for (int i = 0; i < plot.getSize(); i++) {
                    Ellipse2D dot = new Ellipse2D.Double(((getWidth() - plot.getSize()) / 2) + plot.getXAt(i), plot.getYAt(i) + getHeight() / 2, 10, 10);
                    g2d.fill(dot);
                }
            }
            g2d.dispose();
        }
    }
}

null布局不会帮到你,花点时间了解布局管理系统的工作原理,它会为你节省很多时间和精力。有关详细信息,请参阅 Laying Out Components Within a Container

static 不是你的朋友(尤其是在这种情况下),努力了解没有它如何生活(以及何时使用它)