2013-04-06 109 views
4

我试图在Java画布中画两条线,分别调用两个方法,但是当我绘制第二条线时,第一条线消失(Java清除屏幕)。我怎样才能避免这种情况?我想看到两条线。我见过绘画教程(如何制作像Windows上的Paint一样的程序),用户使用鼠标绘制线条,当绘制一条线时,另一条线不会消失。他们只是调用paint方法,并没有清除屏幕。Java在调用paint方法时清除屏幕 - 如何避免这种情况?

如果有人能帮助我,我将不胜感激。 谢谢。

视图类

import java.awt.BorderLayout; 
import java.awt.Canvas; 
import java.awt.Color; 
import java.awt.Graphics; 

import javax.swing.JFrame; 

public class CircuitTracePlotView extends JFrame { 


    private CircuitTracePlot circuitTracePlot; 

    public CircuitTracePlotView() { 


     this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     this.getContentPane().add(circuitTracePlot = new CircuitTracePlot(), BorderLayout.CENTER); 
     this.pack(); 
     this.setSize(250,250); 
     this.setLocationRelativeTo(null); 

     this.setVisible(true); 
     circuitTracePlot.drawLine(); 
     circuitTracePlot.drawOval(); 
    } 


} 

class CircuitTracePlot extends Canvas { 

    private final static short LINE = 1; 
    private final static short OVAL = 2; 
    private int paintType; 

    private int x1; 
    private int y1; 
    private int x2; 
    private int y2; 

    public CircuitTracePlot() { 
     this.setSize(250,250); 
     this.setBackground(Color.WHITE); 

    } 

    private void setPaintType(int paintType) { 
     this.paintType = paintType; 
    } 

    private int getPaintType() { 
     return this.paintType; 
    } 

    public void drawLine() { 
     this.setPaintType(LINE); 
     this.paint(this.getGraphics()); 
    } 

    public void drawOval() { 
     this.setPaintType(OVAL); 
     this.paint(this.getGraphics()); 
    } 

    public void repaint() { 
     this.update(this.getGraphics()); 
    } 

    public void update(Graphics g) { 
     this.paint(g); 
    } 

    public void paint(Graphics g) { 
     switch (paintType) { 
     case LINE: 
      this.getGraphics().drawLine(10, 10, 30, 30);    
     case OVAL: 
      this.getGraphics().drawLine(10, 20, 30, 30); 
     } 


    } 


} 

主要类

import javax.swing.SwingUtilities; 

import view.CircuitTracePlotView; 

public class Main { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       CircuitTracePlotView cr = new CircuitTracePlotView(); 
      } 
     }); 
    } 
} 
+0

+1 [sscce](http://sscce.org/)。 – trashgod 2013-04-06 20:44:26

回答

4
  • 你几乎永远不应该直接调用paint(...)。我一方面可以计算出我需要这样做的时间。
  • 不要通过在组件上调用getGraphics()来获得Graphics对象,因为这将返回非持久Graphics对象。相反,可以绘制一个BufferedImage并在绘制方法中显示或者绘制绘制方法(如果是AWT)。
  • 由于这是一个Swing GUI,请不要使用AWT组件来绘制。使用JPanel并覆盖paintComponent(...)方法,而不是paint(...)方法。否则,您将失去Swing图形的所有优点,包括自动双缓冲。
  • super.paintComponent(g)方法应在paintComponent(Graphics g)重写中调用,通常作为此方法内的第一个方法调用。这让组件可以做自己的家务绘画,包括擦除需要擦除的图纸。
  • 阅读有关Swing图形的教程,因为大部分内容在这里都有很好的解释。对于例如,请看看这里:

编辑

  • 为了使您的图片坚持,我建议你绘制到一个BufferedImage然后在您的JPanel的paintComponent(...)方法中显示该图像。
  • 或者另一个选项是创建一个Shape对象集合,也许是一个ArrayList<Shape>并用它填充想要绘制的图形,然后在paintComponent(...)方法中将Graphics对象转换为Graphics2D对象并迭代Shape在迭代过程中收集每个形状的图形g2d.draw(shape)

由于垃圾张贴了他的代码,...

import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.*; 

public class CircuitTracePlot2 extends JPanel { 

    private static final int PREF_W = 250; 
    private static final int PREF_H = PREF_W; 

    private int drawWidth = 160; 
    private int drawHeight = drawWidth; 
    private int drawX = 10; 
    private int drawY = 10; 
    private PaintType paintType = PaintType.LINE; 

    public CircuitTracePlot2() { 

    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(PREF_W, PREF_H); 
    } 

    public void setPaintType(PaintType paintType) { 
     this.paintType = paintType; 
     repaint(); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     if (paintType == null) { 
     return; 
     } 
     switch (paintType) { 
     case LINE: 
     g.drawLine(drawX, drawY, drawWidth, drawHeight); 
     break; 
     case OVAL: 
     g.drawOval(drawX, drawY, drawWidth, drawHeight); 
     break; 
     case SQUARE: 
     g.drawRect(drawX, drawY, drawWidth, drawHeight); 

     default: 
     break; 
     } 
    } 

    private static void createAndShowGui() { 
     final CircuitTracePlot2 circuitTracePlot = new CircuitTracePlot2(); 

     JFrame frame = new JFrame("CircuitTracePlot2"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(circuitTracePlot); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 

     int timerDelay = 2 * 1000; 
     new Timer(timerDelay , new ActionListener() { 
     private int paintTypeIndex = 0; 

     @Override 
     public void actionPerformed(ActionEvent arg0) { 
      paintTypeIndex++; 
      paintTypeIndex %= PaintType.values().length; 
      circuitTracePlot.setPaintType(PaintType.values()[paintTypeIndex]); 
     } 
     }).start(); 
    } 

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

enum PaintType { 
    LINE, OVAL, SQUARE; 
} 
+0

你能给我摆动图形教程的网址吗?我找不到我想要的东西(也许我找到了你的意思,但我没有看到答案)。我尝试了一些BufferedImage,但我遇到了同样的问题。 – vicaba 2013-04-06 18:16:11

+0

@vicaba:上面添加的链接。有关使用BufferedImages进行绘图的更多信息,可能需要搜索此网站,因为有很多这样的例子,有些是我写的。 – 2013-04-06 18:38:19

+0

@vicaba:也看到的例子,而不是BufferedImage虽然.... – 2013-04-06 18:49:23

2

下面是实现大部分@气垫船的有益的建议对你的程序的变化。尝试注释拨打setPaintType()的电话以查看效果。

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

/** @see http://stackoverflow.com/a/15854246/230513 */ 
public class Main { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       CircuitTracePlotView cr = new CircuitTracePlotView(); 
      } 
     }); 
    } 

    private static class CircuitTracePlotView extends JFrame { 

     private CircuitTracePlot plot = new CircuitTracePlot(); 

     public CircuitTracePlotView() { 
      this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
      plot.setPaintType(CircuitTracePlot.OVAL); 
      this.add(plot, BorderLayout.CENTER); 
      this.pack(); 
      this.setLocationRelativeTo(null); 
      this.setVisible(true); 
     } 
    } 

    private static class CircuitTracePlot extends JPanel { 

     public final static short LINE = 1; 
     public final static short OVAL = 2; 
     private int paintType; 

     public CircuitTracePlot() { 
      this.setBackground(Color.WHITE); 
     } 

     public void setPaintType(int paintType) { 
      this.paintType = paintType; 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      switch (paintType) { 
       case LINE: 
        g.drawLine(10, 10, 30, 30); 
       case OVAL: 
        g.drawOval(10, 20, 30, 30); 
       default: 
        g.drawString("Huh?", 5, 16); 
      } 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(250, 250); 
     } 
    } 
} 
+0

这是行得通!但是......我不知道发生了什么......我会试着解释发生了什么(如果我错了,请纠正我):如果paintComponent()之上的“one”“看到”某个属性也就是paintComponent里面的变化,上面的“one”调用paintComponent()?而且..为什么屏幕现在不清除?与paintComponent()的自动缓冲有关的东西? 非常感谢。 – vicaba 2013-04-06 18:40:24

+0

@vicaba:不客气。有关绘画如何工作的更多信息,请参阅[* AWT和Swing *中的绘画](http://www.oracle.com/technetwork/java/painting-140037.html)。 – trashgod 2013-04-06 20:47:16

相关问题