多次调用paintComponent()

我有这两个类:

public class Pencil extends JComponent implements MouseListener, MouseMotionListener{ Plansa plansa; Graphics g; public Pencil(Plansa newCanvas){ this.plansa = newCanvas; this.plansa.setFlagShape(false); } @Override public void mouseDragged(MouseEvent arg0) { plansa.setMouseDragged(arg0); this.plansa.setFlagShape(false); plansa.paintComponent(plansa.getGraphics()); } @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent arg0) { plansa.setMousePressed(arg0); } @Override public void mouseReleased(MouseEvent arg0) { // TODO Auto-generated method stub plansa.setMouseReleased(arg0); this.plansa.setFlagShape(true); plansa.paintComponent(plansa.getGraphics()); } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseMoved(MouseEvent e) { } } 

还有这个:

 public class Plansa extends JPanel{ Image image; Pencil pencil; //... void init(){ this.setShape("freeLine"); this.setColor(Color.BLACK); this.size=1; this.type="round"; this.fill=false; this.setBackground(Color.WHITE); pencil = new Pencil(this); addMouseListener(pencil); addMouseMotionListener(pencil); flagPaint = true; flagShape = false; } public Plansa(){ this.setSize(800, 600); init(); } //... @Override public void paintComponent(Graphics g) { g.setColor(currentColor); Graphics2D g2d = (Graphics2D) g; g2d.setStroke(setBrush(size,type)); super.paintComponent(g); switch(shape){ default: break; case "freeLine":{ g.drawLine(xDragged, yDragged, xCurrent, yCurrent); break; } case "rectangle":{ if(flagShape == true){ g.drawRect(xPressed, yPressed, Math.max(xCurrent-xPressed,xPressed-xCurrent), Math.max(yCurrent-yPressed,yPressed-yCurrent)); if(fill == true) g.fillRect(xPressed, yPressed, Math.max(xCurrent-xPressed,xPressed-xCurrent), Math.max(yCurrent-yPressed,yPressed-yCurrent)); } break; } case "circle":{ if(flagShape == true){ int radius = (int)Math.sqrt(Math.max(xCurrent-xPressed,xPressed-xCurrent)*Math.max(xCurrent-xPressed,xPressed-xCurrent)+Math.max(yCurrent-yPressed,yPressed-yCurrent)*Math.max(yCurrent-yPressed,yPressed-yCurrent)); g.drawOval(xPressed, yPressed, radius, radius); if(fill == true) g.fillOval(xPressed, yPressed, radius, radius); } break; } case "oval":{ if(flagShape == true){ g.drawOval(xPressed, yPressed, Math.max(xCurrent-xPressed,xPressed-xCurrent), Math.max(yCurrent-yPressed,yPressed-yCurrent)); if(fill == true) g.fillOval(xPressed, yPressed, Math.max(xCurrent-xPressed,xPressed-xCurrent), Math.max(yCurrent-yPressed,yPressed-yCurrent)); } break; } case "line":{ if(flagShape == true){ g.drawLine(xPressed, yPressed, xCurrent, yCurrent); } break; } } } //... } 

我的问题是,每次调用paintComponent()方法时,JPanel都会清除,剩下的唯一项目就是我刚刚绘制的项目。 有什么方法可以避免这种情况吗?

将所有对象存储在ArrayList并在绘制时迭代它。

您可以让它们都实现自定义接口,例如Drawable ,然后存储在ArrayList

仔细检查代码之后,看起来你正在尝试使用Component作为“画家”,这有点像使用跑车作为卡丁车,很多额外的收益。

相反,您应该自己定义一个kine的接口,它提供您想要绘制/绘制的基本要求,然后定义实现该function的具体类实现。

然后,您将维护一个可以绘制的所有图纸的List

虽然简单,但下面的示例提供了一个可以增强的跳出点,允许选择图纸,重新排序和删除(如果您需要)。

这基本上与Doorknob(+1)提出的概念相同

在此处输入图像描述

 import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.Line2D; import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class TestDraw { public static void main(String[] args) { new TestDraw(); } public TestDraw() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new Pencil()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class Pencil extends JPanel implements MouseListener, MouseMotionListener { private List drawables; private Drawable activeDrawable; private Point clickPoint; public Pencil() { drawables = new ArrayList<>(5); addMouseListener(this); addMouseMotionListener(this); } @Override public Dimension getPreferredSize() { return new Dimension(400, 400); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); for (Drawable drawable : drawables) { drawable.paint(g2d); } g2d.dispose(); } @Override public void mouseDragged(MouseEvent e) { if (activeDrawable != null) { Point p = e.getPoint(); Rectangle bounds = activeDrawable.getBounds(); int x = bounds.x; int y = bounds.y; int width = px - clickPoint.x; int height = py - clickPoint.y; if (width < 0) { width *= -1; x = px; } if (height < 0) { height *= -1; y = py; } bounds = new Rectangle(x, y, width, height); System.out.println(bounds); activeDrawable.setBounds(bounds); repaint(); } } @Override public void mouseClicked(MouseEvent e) { } protected Drawable createActiveShape(MouseEvent e) { System.out.println("Anchor = " + e.getPoint()); Drawable drawable = new FreeLine(e.getPoint()); drawable.setLocation(e.getPoint()); return drawable; } @Override public void mousePressed(MouseEvent e) { // You could also check to see if the clicked on a drawable... clickPoint = e.getPoint(); activeDrawable = createActiveShape(e); drawables.add(activeDrawable); repaint(); } @Override public void mouseReleased(MouseEvent e) { if (activeDrawable != null) { Rectangle bounds = activeDrawable.getBounds(); if (bounds.width == 0 || bounds.height == 0) { drawables.remove(activeDrawable); } } clickPoint = null; activeDrawable = null; } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseMoved(MouseEvent e) { } } public interface Drawable { public void setLocation(Point p); public void setSize(Dimension dim); public void setBounds(Rectangle bounds); public Rectangle getBounds(); public void paint(Graphics2D g2d); } public abstract class AbstractDrawable implements Drawable { private Rectangle bounds; public AbstractDrawable() { bounds = new Rectangle(); } @Override public void setLocation(Point p) { bounds.setLocation(p); } @Override public void setBounds(Rectangle bounds) { this.bounds = bounds; } @Override public void setSize(Dimension dim) { bounds.setSize(dim); } @Override public Rectangle getBounds() { return bounds; } } public class FreeLine extends AbstractDrawable { private Point anchor; public FreeLine(Point anchor) { this.anchor = anchor; } @Override public void paint(Graphics2D g2d) { Rectangle bounds = getBounds(); Point p1 = new Point(anchor); Point p2 = new Point(bounds.getLocation()); if (p1.x > p2.x) { p2.x = p1.x - bounds.width; } else { p2.x = p1.x + bounds.width; } if (p1.y > p2.y) { p2.y = p1.y - bounds.height; } else { p2.y = p1.y + bounds.height; } g2d.draw(new Line2D.Float(p1, p2)); } } 

对于渐进式绘图而言,更好的想法是使用BufferedImage作为canvas,如此处所示。

不要使用/注释掉:

 super.paintComponent(g); 

那条线正在进行清算。