2017-01-01 75 views
2

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

如何解决呢?

+0

你应该从一个单独的线程调用'drawLine'。 'repaint'可安全地从EDT外部调用,并通过调用'drawLine'(其中包含'sleep()')来阻止EDT。 – Calculator

回答

3

我会解决这个问题与屏幕外图像,这样你就不必省略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();; 
     }); 
    } 

} 

,你有时会看到一条线,有时只是一个单点的原因是挥杆合并连续的repaint()在短时间内发生的呼叫。

+0

谢谢,BufferedImage是一个很好的解决方案。 – Sigma

+0

@Sigma:这是你想要的解决方案(+1)。你可能会考虑把'g.drawImage(...)'包装在一个if块中,if(offi!= null)'如果它有可能是空的话。 –

+0

不需要paintComponent(...)方法上的“synchronized”关键字。所有Swing绘画代码都在事件派发线程(EDT)上执行。 – camickr

2

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

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

    } 

} 

这是一个糟糕的设计,但我做了它来证明你必须做的。最好的情况是创建一个Point类并将你的点存储在ArrayList中。

+0

如果我删除Thread.sleep(),我只看到一个点 – Sigma

+0

这取决于你如何让你的线被绘制。 – ddarellis

相关问题