Java 如何在swing中重新绘制而不删除以前绘制的对象

Java 如何在swing中重新绘制而不删除以前绘制的对象,java,swing,graphics,awt,Java,Swing,Graphics,Awt,所以,我想用java和swing实现DDA算法来画线,但这里有一个小问题。要绘制每个像素,我使用fillRect(X,Y,1,1)。因此,我需要为X和Y的不同位置绘制一条线。为了更新新绘制的“像素”,我正在使用revalidate()和repaint()但这似乎删除了我以前绘制的像素,我只看到了一点。作为一种解决方法,我在我的paintComponent(Graphics)中注释掉了super.paintComponent(g),但这似乎不是一个好的解决方案,因为这样我就无法设置背景色,如果我使

所以,我想用java和swing实现DDA算法来画线,但这里有一个小问题。要绘制每个像素,我使用
fillRect(X,Y,1,1)
。因此,我需要为
X
Y
的不同位置绘制一条线。为了更新新绘制的“像素”,我正在使用
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) {

        }

    }

}

如何修复它?

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

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) {

    }

}
private final List points=new ArrayList();
@凌驾
受保护组件(图形g){
超级组件(g);
挫折背景(颜色:黑色);
g、 setColor(Color.RED);
用于(阵列列表点:点){
g、 fillRect(point.get(0),point.get(1),1,1);
}
}
公共空水位线(){
双DX=(x2-x1);
双DY=(y2-y1);
双步骤=(Math.abs(DX)>Math.abs(DY))?Math.abs(DX):Math.abs(DY);
双x增量=((双)DX/(双)(步数));
双阴增量=((双)DY/(双)(步数));
试一试{
对于(int i=0;i

这是一个糟糕的设计,但我做它来演示你必须做什么。最好的情况是创建一个Point类并将点存储在
数组列表中

我将使用屏幕外图像解决问题,这样您就不必忽略
super.paintComponent()

导入java.awt.Color;
导入java.awt.Graphics;
导入java.awt.image.buffereImage;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.SwingUtilities;
公共类油漆工扩展JPanel{
缓冲图像办公室;
制图主任;
专用双x1,y1,x2,y2;
油漆工(内部x1、内部y1、内部x2、内部y2){
这是1.x1=x1;
这是1.y1=y1;
这是0.x2=x2;
这1.y2=y2;
}
@凌驾
受保护的组件(图形g){
超级组件(g);
g、 drawImage(offi,0,0,this);
}
私人提款(){
if(offi==null){
OFI=(BuffereImage)createImage(getWidth(),getHeight());
offg=offi.getGraphics();
offg.setColor(颜色为黑色);
offg.fillRect(0,0,getWidth(),getHeight());
}  
offg.setColor(颜色为红色);
副秘书长(内部)x1,(内部)y1,1,1);
}
公共空水位线(){
双DX=(x2-x1);
双DY=(y2-y1);
双步骤=(Math.abs(DX)>Math.abs(DY))?Math.abs(DX):Math.abs(DY);
双X增量=DX/(步);
双yIncrement=DY/(步);
对于(int i=0;i{
JFrame JFrame=新JFrame(“图形”);
油漆工dpl=新油漆工(0,0533333);
jFrame.add(dpl);
jFrame.setSize(720480);
jFrame.setresizeable(false);
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(jFrame.EXIT_ON_CLOSE);
新螺纹(()->dpl.drawLine()).start();;
});
}
}

有时会看到一条线,有时只看到一个点,原因是swing会合并在短时间内发生的连续调用。

这取决于您希望如何绘制线。您应该从单独的线程调用
drawLine
<代码>重绘
可以安全地从EDT外部调用,您可以通过调用EDT上的
绘图线
(其中包含
sleep()
)来阻止EDT。@西格玛:这是您想要的解决方案(+1)。在IF块中,可以考虑包装<代码> G.DRAWMAMAGE(…)<代码>,<代码> if(Offi!= NULL)< /代码>如果它有可能是NULL。不需要PrimtCe组件(…)方法上的“同步”关键字。所有Swing绘制代码都在事件调度线程(EDT)上执行。@camickr我认为,由于我在回答中使用了单独的动画线程,
paintComponent()
中的代码可能必须与
draw()中的代码同步。单独同步
paintComponent()
确实毫无意义,但我认为使
draw
同步可能比从
paintComponent()
中删除同步的更干净,因为
buffereImage
不是完全线程安全的。
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) {

    }

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

}