如何在不删除以前绘制的东西的情况下重新绘制 swing

How to re-draw in swing without removing previously drawn things

所以,我想实现 DDA 算法以使用 java 和 swing 画线,但我在这里遇到了一点问题。为了绘制每个像素,我使用 fillRect(X,Y,1,1)。所以,我需要为 XY 的不同位置画一条线。为了更新新绘制的 'pixel' 我正在使用 revalidate()repaint() 但这似乎删除了我以前绘制的像素,我只看到一个点。作为解决方法,我在我的 paintComponent(Graphics) 中注释掉了 super.paintComponent(g) 但这似乎不是一个好的解决方案,因为那样我就无法设置背景颜色,如果我放慢速度,我会看到正在绘制线条使用Thread.sleep()(否则我只看到一个点)。这是代码

import javax.swing.*;
import java.awt.*;

public class Painter extends JPanel {
    private double x1,y1,x2,y2;
    Painter(int x1, int y1, int x2, int y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;

    }
    @Override
    protected void paintComponent(Graphics g) {
        //super.paintComponent(g);
        setBackground(Color.black);
        g.setColor(Color.RED);
        g.fillRect((int)x1,(int)y1,1,1);
    }

    public void drawLine() {
        double DX = (x2-x1);
        double DY = (y2-y1);

        double steps = (Math.abs(DX) > Math.abs(DY) ) ? Math.abs(DX) : Math.abs(DY);

        double xIncrement = DX/(steps);
        double yIncrement = DY/(steps);
        try {
            for (int i = 0; i < steps; ++i) {
                Thread.sleep(50);
                x1 += xIncrement;
                y1 += yIncrement;
                revalidate();
                repaint();
            }
        }
        catch (Exception e) {

        }

    }

}

从我的 main() 我称之为

JFrame jFrame = new JFrame("Graphics");
Painter dpl = new Painter(0,0,533,333);
jFrame.add(dpl);
jFrame.setSize(720,480);
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
dpl.drawLine();

如何解决?

您应该跟踪您当前的点以重新绘制它们。

private final List<ArrayList<Integer>> points = new ArrayList<ArrayList<Integer>>();

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    setBackground(Color.black);
    g.setColor(Color.RED);
    for(ArrayList<Integer> point : points) {
        g.fillRect(point.get(0),point.get(1),1,1);
    }
}

public void drawLine() {
    double DX = (x2-x1);
    double DY = (y2-y1);

    double steps = (Math.abs(DX) > Math.abs(DY) ) ? Math.abs(DX) : Math.abs(DY);

    double xIncrement = ((double)DX/(double)(steps));
    double yIncrement = ((double)DY/(double)(steps));
    try {
        for (int i = 0; i < steps; ++i) {
            Thread.sleep(50);
            x1 += xIncrement;
            y1 += yIncrement;

            points.add(new ArrayList<Integer>(){{add((int)x1); add((int)y1);}});
            revalidate();
            repaint();
        }
    }
    catch (Exception e) {

    }

}

这是一个糟糕的设计,但我制作它是为了演示您必须做什么。最好的情况是创建一个点 class 并将您的点存储在 ArrayList.

我会用离屏图像解决问题,这样你就不必省略 super.paintComponent();:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

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

public class Painter extends JPanel {
    BufferedImage offi;
    Graphics offg;
    private double x1,y1,x2,y2;

    Painter(int x1, int y1, int x2, int y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;

    }
    @Override
    protected synchronized void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(offi,0,0,this);
    }

    private void draw(){
        if(offi == null){
            offi = (BufferedImage)createImage(getWidth(),getHeight());
            offg = offi.getGraphics();
            offg.setColor(Color.black);
            offg.fillRect(0,0,getWidth(),getHeight());
        }  
        offg.setColor(Color.RED);
        offg.fillRect((int)x1,(int)y1,1,1);
    }

    public void drawLine() {
        double DX = (x2-x1);
        double DY = (y2-y1);

        double steps = (Math.abs(DX) > Math.abs(DY) ) ? Math.abs(DX) : Math.abs(DY);

        double xIncrement = DX/(steps);
        double yIncrement = DY/(steps);        
        for (int i = 0; i < steps; ++i) {           
            x1 += xIncrement;
            y1 += yIncrement;

            /*try{
                Thread.sleep(50); //sleep if you want it to be animated
            }catch(InterruptedException e){
                e.printStackTrace();
            }*/
            draw();            
            repaint();
        }  
    }

    public static void main(String[] args){
        SwingUtilities.invokeLater(() -> {
            JFrame jFrame = new JFrame("Graphics");
            Painter dpl = new Painter(0,0,533,333);
            jFrame.add(dpl);
            jFrame.setSize(720,480);
            jFrame.setResizable(false);
            jFrame.setVisible(true);
            jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            new Thread(() -> dpl.drawLine()).start();;
        });
    }

}

您有时看到一条线有时只看到一个点的原因是 swing 合并了短时间内发生的连续 repaint() 调用。