在JFrame中使用paint()时出错了

时间:2014-03-25 12:48:23

标签: java swing

当我尝试在JFrame中绘制一个椭圆时,paint()方法不起作用,但是当我将JFrame更改为Frame时,它很好。你能解释一下这个问题吗?

import java.awt.Graphics;
import java.awt.Window;

import javax.swing.JFrame;

public class Oval extends JFrame
{
    public Oval()
    {
    //  this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setSize(400, 400);
    }

    public void paint(Graphics g)
    {
        g.drawOval(40, 40, 40, 40);
    }

    public static void main(String []args)
    {
        new Oval();
    }
}

2 个答案:

答案 0 :(得分:3)

  1. 不要覆盖paint()。而是将JPanel添加到JFrame并覆盖paintComponent(g)

  2. 调用super方法。即使您覆盖paint()来电super.paint()(当然,最好使用paintComponnet()

答案 1 :(得分:2)

您不应该覆盖paint()方法,而是向JPanel添加JFrame并覆盖JPanel's paintComponent()方法并绘制你在JPanel上的东西。

这是一个示范:

import javax.swing.*;
import java.awt.*;

public class Oval extends JFrame
{
  public Oval()
  {
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setLayout(new GridBagLayout());

    OvalPanel ovalPanel = new OvalPanel(100); // SIZE of oval is 100
    ovalPanel.setPreferredSize(new Dimension(400, 400));

    add(ovalPanel);
    pack();
    setLocationRelativeTo(null);
    setVisible(true);
  }

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new Runnable()
    {
      @Override
      public void run()
      {
        new Oval();
      }
    });
  }
}

class OvalPanel extends JPanel
{
  private final int SIZE;

  public OvalPanel(final int size)
  {
    this.SIZE = size;
  }

  @Override
  public void paintComponent(Graphics g)
  {
    super.paintComponent(g); // Call the super class's paintComponent so that it does its appropriate rendering first.
    g.drawOval((getWidth() - SIZE) >> 1, (getHeight() - SIZE) >> 1, SIZE, SIZE); // Center the oval
  }
}

另外如果您注意到,我使用了SwingUtlities.invokeLater()方法,并在那里调用了Oval构造函数。我这样做是因为Swing是线程不安全的,所以你应该在Event Dispatcher Thread中调用任何与Swing相关的方法,它负责处理任何与Swing相关的东西,以及invokeLater()方法的作用。

注意:如果您使用的是JDK 8,则可以将SwingUtilities.invokeLater()语句写为:

SwingUtilities.invokeLater(Oval::new); // That's JDK 8 Method reference feature.

您可能想知道为什么不应该直接在paint()方法中执行操作。原因与调用paint()方法的方式有关。你看,RepaintManager负责处理所有基于Swing的组件的绘制,当调用paint()方法时,它又调用paintComponent()paintChildren()paintBorder()方法。 paintComponent()是处理任何基于组件的渲染的最佳位置,这也是其建议的原因。但是,即使以下代码也可以:

import javax.swing.*;
import java.awt.*;

public class Oval extends JFrame
{
  public Oval()
  {
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(400, 400);
    setLocationRelativeTo(null);
    setVisible(true);
  }

  public void paint(Graphics g)
  {
    super.paint(g); // Calling the super class's paint method first.
    // so that it handles its rendering.
    g.drawOval(40, 40, 40, 40);
  }

  public static void main(String[] args)
  {
    new Oval();
  }
}

甚至调用方法的顺序在Swing中也很重要。喜欢:

setSize(400, 400); // Setting the size of JFrame first.
setLocationRelativeTo(null); // Locating the JFrame based on its size then.
setVisible(true); // Finally its made visible

以上所有工作都符合预期。但以下内容未能正确显示结果:

setVisible(true); // JFrame is already made visible
setLocationRelativeTo(null); // This first locates the JFrame based on its (0, 0) size
setSize(400, 400); // Then its size is increased. Not as expected as the JFrame appears shifted from center.