不重绘旧元素就无法重绘新元素

Cannot repaint new elements without repainting old ones

这是我的问题:

我制作了一个在随机位置绘制正方形的程序,它有点粗糙但是可以用。 但是问题是它不会正确重绘,我不知道在哪里但是我在代码的某个地方犯了错误。

这会导致以下情况发生:我告诉应用程序绘制 5 个正方形,它确实这样做了,但是当我告诉它绘制 6 个时,它会绘制前一个 5 + 6。

下面列出了代码,分两部分 RandomSquares 和 DrawField :

public class RandomSquares extends JPanel {

private static JFrame frame = new JFrame("Random Squares");
private static DrawField f;
private static JButton button = new JButton("Make squares");
private static final JTextField field = new JTextField(10);
private static int amount = 0;

private static void prepareFrame() {
    //knoppen

    button.addActionListener(new ActionListener()
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
                System.out.println(amount);
                amount = Integer.parseInt(field.getText());
                f = new DrawField(amount);
                frame.add(f, BorderLayout.CENTER);

                frame.repaint();


        }

    });

    frame.add(button, BorderLayout.NORTH);
    frame.add(field, BorderLayout.SOUTH);

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    Listener l = new Listener(); 
    frame.addKeyListener(l);
    frame.setSize(640, 480);

}

public static class Listener implements KeyListener {

        @Override
        public void keyTyped(KeyEvent ke) {
            //unused
        }

        @Override
        public void keyPressed(KeyEvent ke) {
            if (ke.getKeyCode() == KeyEvent.VK_R) {
                System.out.println("woot!");
            }
        }

        @Override
        public void keyReleased(KeyEvent ke) {
            //unused
        }       

}


public static void run() {
    f = new DrawField(amount);
    prepareFrame();

    frame.setVisible(true);
}
}

public class DrawField 扩展 JComponent {

private int amount;

public int getAmount() {
    return amount;
}

public void setAmount(int amount) {
    this.amount = amount;
}

public DrawField(int amount) {
    this.amount = amount;
    this.setSize(540, 380);
    this.setBackground(Color.GREEN);
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Random r = new Random();
    for (int i = 0; i < amount; i++) {


                g.fillRect(r.nextInt(getWidth()), r.nextInt(getHeight()),
                        20, 20);
        }

    }
}

I tell the application to draw 5 squares it does so but then when I tell it to draw 6 it will draw the previous 5 + 6.

组件未清除任何先前的绘制调用 - 请确保始终调用父绘制方法以清除任何先前的绘制。例如:

@Override
protected void paintComponent(Graphics g){
    super.paintComponent(g);
    //custom painting here.
}

绘画方法只能用于绘画,不能设置你的属性class。

g.fillRect(r.nextInt(getWidth()), r.nextInt(getHeight()), 20, 20);

例如,如果您调整框架的大小,将在新的随机位置绘制一组全新的矩形。

当您调用 super.paintComponent() 时,旧绘图将丢失并创建新的随机矩形。

相反,您的绘画代码应该基于 class 的属性。也就是说,一旦您创建了对象,它们就应该被修复,因此重新绘制组件不会改变绘制,除非您更改属性。

请参阅 Custom Painting Approaches,了解如何使用随机数量的对象进行绘画的示例:

  1. 保留要绘制的对象列表
  2. 将对象添加到 BufferedImage,然后只绘制图像。

在您的情况下,您将为要绘制的指定数量的矩形调用 addRectangles(...) 方法。然后绘画代码将完成剩下的工作。

编辑:

回答你的基本问题。一般来说,你需要调用super.paintComponent()来清除组件的背景,然后再进行组件的自定义绘制。

问题是您正在扩展 JComponent,它没有任何默认绘画代码,因此背景不会被清除。两种解决方案:

  1. 改为扩展 JPanel(JPanel 会清除背景)。
  2. 将自定义绘画代码添加到您的 class 以清除背景:

类似于:

g.setColor( getBackground() );
f.fillRect(0, 0, getWidth(), getHeight());
// paint rectangle here