【问题标题】:Java clears screen when calling paint method - how to avoid that?Java在调用paint方法时清除屏幕 - 如何避免这种情况?
【发布时间】:2013-03-29 01:15:06
【问题描述】:

我试图在 Java 中的 Canvas 中绘制两条线,分别调用两个方法,但是当我绘制第二条线时,第一条线消失(Java 清除屏幕)。我怎样才能避免这种情况?我想看看这两条线。我看过画图教程(如何在 Windows 上制作像画图这样的程序),其中用户使用鼠标画线,当画出一条线时,另一条线不会消失。他们只是调用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();
            }
        });
    }
}

【问题讨论】:

标签: java screen paint java-canvas


【解决方案1】:
  • 您几乎不应该直接致电paint(...)。一方面,我可以数出我需要执行此操作的次数。
  • 不要通过在组件上调用 getGraphics() 来获取 Graphics 对象,因为这将返回一个非持久的 Graphics 对象。而是在 BufferedImage 中绘制并在paint 方法中显示它,或者在paint 方法中绘制(如果是AWT)。
  • 因为这是一个 Swing GUI,所以不要使用 AWT 组件来绘制。使用 JPanel 并覆盖 paintComponent(...) 方法,而不是 paint(...) 方法。否则,您将失去 Swing 图形的所有优势,包括自动双缓冲。
  • super.paintComponent(g) 方法应在paintComponent(Graphics g) 覆盖中调用,通常作为该方法内部的第一个方法调用。这让组件可以自己做家务绘制,包括擦除需要擦除的绘图。
  • 阅读有关 Swing 图形的教程,因为其中大部分内容都得到了很好的解释。例如,请看这里:

编辑

  • 为了让您的图像持久存在,我建议您绘制到 BufferedImage,然后在 JPanel 的 paintComponent(...) 方法中显示该图像。
  • 或者另一种选择是创建一个 Shape 对象集合,可能是一个 ArrayList<Shape> 并用您想要绘制的 Shapes 填充它,然后在 paintComponent(...) 方法中将 Graphics 对象转换为 Graphics2D 对象并遍历 Shape 集合,在您迭代时使用 g2d.draw(shape) 绘制每个形状。

自从 Trash 发布了他的代码,...

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

【讨论】:

  • 可以给我挥杆图形教程的网址吗?我找不到我想要的东西(也许我找到了你的意思的教程,但我没有看到答案)。我用 BufferedImage 尝试了一些东西,但我遇到了同样的问题。
  • @vicaba:上面添加了链接。有关使用 BufferedImages 绘图的更多信息,您可能需要搜索此站点,因为有很多示例,其中一些是我编写的。
  • @Hovercraft_Full_Of_Eels:谢谢,我想我知道的不够多,无法理解上面链接的教程中解释的所有内容。但是,我确实理解您在解释什么以及解决我的问题的不同方法。现在我将使用 +trashgod 方式(我认为您在上面解释的第一种方式)。我将来会回到这里来实施你的其他方法。感谢您的信息!
  • +Hovercraft_Full_Of_Eels:好的,这更专业.. 谢谢@trashgod 和 Hovercraft。
  • @Hovercraft .....你有一个方法的例子,更新 BufferedImage 然后只显示?,或者有一个集合?我真的很想知道该怎么做,特别是第二个......谢谢:)
【解决方案2】:

这是您的程序的一个变体,它实现了@Hovercraft 的许多有用建议。尝试注释掉对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);
        }
    }
}

【讨论】:

  • 行得通!但是......我无法意识到发生了什么......我会尝试解释发生了什么(如果我错了,请纠正我):如果在paintComponent()之上的“一个”“看到”某个属性那是在paintComponent内部发生变化,上面的“一个”调用paintComponent()?还有..为什么现在屏幕没有清除?与paintComponent() 的自动缓冲有关的东西?非常感谢。
  • @vicaba:不客气。有关绘画如何工作的更多信息,请参阅Painting in AWT and Swing
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多