如何阻止JComponent清除?

时间:2014-03-11 00:07:53

标签: java swing mouseevent paintcomponent repaint

我正在制作分子设计应用程序。我可以绘制线条和圆圈,但每次单击时它都会清除旧线条,所以基本上,你只能设计具有2个原子的分子。 此外,如果单击非常快,则mouseEvents不会传递,这也是一个问题。 这是代码:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;

import javax.swing.JComponent;
import javax.swing.JFrame;
public class MoleculeDesigner extends JComponent implements MouseListener {
    private Point op, cp;
    private boolean first = true;
    public static final Color linecolor = new Color(0, 255, 0);
    private static final long serialVersionUID = 1L;
    private BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
    public MoleculeDesigner() {
        JFrame f = new JFrame("Molecule Designer");
        f.setBackground(Color.WHITE);
        f.addMouseListener(this);
        f.add(this);
        f.setSize(100, 100);
        f.setDefaultCloseOperation(3);
        f.setVisible(true);
    }
    public static void main(String[] args) {
        new MoleculeDesigner();
    }
    @Override
    protected void paintComponent(Graphics g) {
        if(op != null && cp != null) {
            Graphics2D g2 = img.createGraphics();
            super.paintComponent(g2);
            g2.setColor(linecolor);
            g2.drawLine((int) op.getX(), (int) op.getY(), (int) cp.getX(), (int) cp.getY());
            g2.setColor(Color.BLACK);
            g2.fillOval((int) cp.getX(), (int) cp.getY(), 10, 10);
            op = (Point) cp.clone();
            g2.dispose();
        }
    }
    @Override
    public Dimension getPreferredSize() {
        return getParent().getMaximumSize();
    }
    @Override
    public void mouseClicked(MouseEvent e) {
        if(!first) {
            cp = e.getPoint();
            cp.setLocation(cp.getX(), cp.getY() - 8);
        }
        else {
            op = e.getPoint();
            first = false;
        }
        repaint();
    }
    @Override public void mousePressed(MouseEvent e) {}
    @Override public void mouseReleased(MouseEvent e) {}
    @Override public void mouseEntered(MouseEvent e) {}
    @Override public void mouseExited(MouseEvent e) {}
}

所有帮助表示赞赏!

2 个答案:

答案 0 :(得分:4)

1)绘制BufferedImage然后显示在paintComponent覆盖内部,或者2)将数据放入ArrayList或其他集合中,然后遍历paintComponent内的集合。如果我将数据用于其他目的,我会做后者。此外,永远不要这样做:

public void update(Graphics g) {
    paintComponent(g);
}

这不是Swing图形应该如何完成的,而且是潜在危险的代码。请阅读:


修改
关于选项1的更多细节:

  • 使用其构造函数之一创建BufferedImage。
  • 在图像上绘图。
    • 当您需要绘制时,使用getGraphics()createGrahpics()(对于Graphics2D对象)从BufferedImage获取Graphics对象
    • 使用此图形对象绘制
    • 然后dispose()图形对象。
  • 然后调用repaint()让JVM重新绘制组件。
  • 通过调用paintComponent,在您的g.drawImage(...)方法中绘制图像,并传入缓冲的图像。

好处:通常绘图更快,我经常使用它来绘制背景图像 缺点:数据点不可用,因此如果您需要对数据点进行操作或动画,这不是可行的方法。

答案 1 :(得分:3)

你没有,也不应该。

Swing中的

paint是一个破坏性的过程,这就是它的设计方式。也就是说,期望当您要求组件绘制自己时,它会在绘制任何内容之前清理Graphics上下文(尽管透明组件略有不同)。

Swing没有关于组件之前绘制的内容的概念,因为Graphics上下文是在绘制的所有组件之间共享的,除非您先清除图形,否则最终会出现不需要的绘制工件

可能的解决方案可能包括......

  1. 绘制到某种支持缓冲区(例如BufferedImage),使用paintComponent方法绘制。这是有限的,因为它只是一个绘画程序,为图像绘制像素。当可见区域的大小发生变化时,您还需要提供功能,因为BufferedImage将不知道。
  2. 将您想要绘制的每个对象放入某种List并在调用paintComponent时迭代此列表。这更灵活一点,你可以控制绘制对象的顺序,删除对象并在你喜欢的地方插入新对象