Java在调用paint方法时清除屏幕 - 如何避免这种情况?
我试图在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();
}
});
}
}
- 你几乎永远不应该直接调用
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;
}
你能给我摆动图形教程的网址吗?我找不到我想要的东西(也许我找到了你的意思,但我没有看到答案)。我尝试了一些BufferedImage,但我遇到了同样的问题。 – vicaba 2013-04-06 18:16:11
@vicaba:上面添加的链接。有关使用BufferedImages进行绘图的更多信息,可能需要搜索此网站,因为有很多这样的例子,有些是我写的。 – 2013-04-06 18:38:19
@vicaba:也看到的例子,而不是BufferedImage虽然.... – 2013-04-06 18:49:23
下面是实现大部分@气垫船的有益的建议对你的程序的变化。尝试注释拨打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://*.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()之上的“one”“看到”某个属性也就是paintComponent里面的变化,上面的“one”调用paintComponent()?而且..为什么屏幕现在不清除?与paintComponent()的自动缓冲有关的东西? 非常感谢。 – vicaba 2013-04-06 18:40:24
@vicaba:不客气。有关绘画如何工作的更多信息,请参阅[* AWT和Swing *中的绘画](http://www.oracle.com/technetwork/java/painting-140037.html)。 – trashgod 2013-04-06 20:47:16
+1 [sscce](http://sscce.org/)。 – trashgod 2013-04-06 20:44:26