在Java中创建矩形时,我是否实际调用了paintComponent方法?

时间:2012-04-20 02:27:22

标签: java swing jframe jpanel jcomponent

这是我当前的RectangleComponent类,我将它添加到我的主JFrame中的面板,但它永远不会出现。我认为它不是绘图所以我决定在Rectangle的构造函数中调用paintComponent方法,并在通过4-5 nullPointerExceptions进行排序后,没有任何更改。我已经阅读了有关如何绘制矩形的多个指南,并且我已经看到了多个代码示例,但我永远无法让面板与多个JComponent一起使用。如果可以,请简要查看我的代码,看看您是否可以设计解决方案。 感谢您的时间。还列出了我在中调用矩形构造函数的框架。

public class GameFrame extends JFrame
{
    private SpellBarComponent bar;
    private JPanel mainPanel = new JPanel();
    private JPanel buttonPanel = new JPanel();
    private JPanel healthPanel = new JPanel();
    Color green = new Color(29, 180, 29);
    Color red = new Color(255, 0, 0);
    private RectangleComponent life;
    private RectangleComponent death;
    private JFrame frame = new JFrame();

    public GameFrame(char x)
    {
        frame.setSize(1024, 768);
        frame.setTitle("Game");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        FlowLayout layout = new FlowLayout();
        createPanels(x);
        healthPanel.setLayout(layout);
        buttonPanel.setLayout(layout);
        mainPanel.setLayout(layout);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        repaint();
    }

    public RectangleComponent getLife()
    {
        return life;
    }

    private void createHealth()
    {
        life = new RectangleComponent(green, healthPanel);
        death = new RectangleComponent(red, healthPanel);
    }

    private void createPanels(char x)
    {
        add(healthPanel);
        pack();
        createBar(x);
        createHealth();
        mainPanel.add(buttonPanel);
        mainPanel.add(healthPanel);
        healthPanel.add(death);
        healthPanel.add(life);
        buttonPanel.add(bar.getSpell1());
        buttonPanel.add(bar.getSpell2());
        buttonPanel.add(bar.getSpell3());
        add(mainPanel);
    }

    private void createBar(char x)
    {
        bar = new SpellBarComponent(x, mainPanel);
    }
}


public class RectangleComponent extends JComponent
{
    Color color;
    int width;
    int height = 18;
    RoundRectangle2D roundedRectangle;
    private JPanel panel;
    public RectangleComponent(Color color, JPanel panel)
    {
        this.panel = panel;
        this.color = color;
        paintComponent(panel.getGraphics());
    }

    public void paintComponent(Graphics g)
    {
        Graphics2D graphics2 = (Graphics2D) g;
        width = 125;
        roundedRectangle = new RoundRectangle2D.Float(10, 10, width, height, 10, 10);
        graphics2.setPaint(color);
        graphics2.fill(roundedRectangle);
        graphics2.draw(roundedRectangle); 
    }

    public void subtractLife(int amount)
    {
        width -= amount;
        roundedRectangle.setRoundRect(10, 10, width, height, 10, 10);
        repaint();
    }
}

3 个答案:

答案 0 :(得分:3)

无需将JPanel传递给RectangleComponent的构造函数,只需获取Graphics,无需手动调用paintComponent。见Painting in AWT and Swing。查看此example,演示绘制矩形的自定义组件。

答案 1 :(得分:3)

你的代码有点创意,有点疯狂,并且逻辑非常难以理解。最不寻常的方面是它有两个JFrame,一个叫做“frame”,一个是GameFrame对象本身,两个都添加了组件,但只有一个显示。您还有许多返回void的方法(如果过度使用会增加代码味道),只会增加使代码更加混乱。

例如,

public GameFrame(char x) {

  // here you set up the "frame" JFrame
  frame.setSize(1024, 768);
  frame.setTitle("Game");
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.setVisible(true);
  FlowLayout layout = new FlowLayout();
  createPanels(x);
  healthPanel.setLayout(layout);
  buttonPanel.setLayout(layout);
  mainPanel.setLayout(layout);

  // here you add content to the frame JFrame, and pack it
  frame.getContentPane().add(mainPanel);
  frame.pack();
  repaint();  // and then call repaint on the "this" JFrame?
}

public RectangleComponent getLife() {
  return life;
}

private void createHealth() {
  life = new RectangleComponent(green, healthPanel);
  death = new RectangleComponent(red, healthPanel);
}

private void createPanels(char x) {
  add(healthPanel); // now you add content to the "this" JFrame
  pack();  // and pack it
  createBar(x);
  createHealth();
  mainPanel.add(buttonPanel);
  mainPanel.add(healthPanel); // and then re-add a JPanel into a second JPanel?
  healthPanel.add(death);
  healthPanel.add(life);
  buttonPanel.add(bar.getSpell1());
  buttonPanel.add(bar.getSpell2());
  buttonPanel.add(bar.getSpell3());
  add(mainPanel); // and then re -add the mainPanel into the "this" JFrame???
}

这一切都非常令人困惑,并且不太可能起作用。

然后你试图直接调用paintComponent并在JComponent上调用getGraphics,这两个都不应该完成。您将需要浏览图形教程以了解如何正确执行此操作。

我建议你考虑重写这个,首先,只使用一个JFrame,并更好地组织你的代码。

答案 2 :(得分:3)

为了使您的Swing应用程序按预期工作,您需要记住许多事项。为了逃避可能出现的某些障碍,必须遵循一定的步骤,因为您以错误的方式编码。为了坚持Swing Programming的基础知识,并遵循它们。

  • 就像@HovercraftFullOfEels所提到的那样,你打电话给你 图形直接,哪一个不应该做。

  • 其次,查看您设置的GameFrame()构造函数 即使在您添加任何组件之前,也可以看到它们 在它的实际尺寸确定之前

编码中的这些循环漏洞可能会引起很多麻烦,因为你坐下来编写大型程序,所以最好从一开始就走在安全的道路上,然后在后期诅咒自己。正如他们所说预防胜于治疗。

现在进入你的程序,你错过了主要的东西,因为你没有指定CustomComponent的大小,即JComponent,因此你无法在屏幕上看到它。当您将JCompoent扩展到您的班级时,请将其设为惯用的习惯,以覆盖getPreferredSize(),与覆盖paintComponent(...)方法的方式相同。

看看这个小程序,我为你精心设计,可能会帮助你,更多地理解逻辑。

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import javax.swing.*;

public class CustomPainting {

    private RectangleComponent life;
    private RectangleComponent death;

    private void createAndDisplayGUI() {
        JFrame frame = new JFrame("Custom Painting");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel centerPanel = new JPanel();
        centerPanel.setLayout(new GridLayout(0, 2, 5, 5));
        // Specifying the WIDTH, HEIGHT and Colour for this JComponent.
        life = new RectangleComponent(Color.GREEN.darker(), 20, 20);
        death = new RectangleComponent(Color.RED.darker(), 20, 20);
        centerPanel.add(life);
        centerPanel.add(death);

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
        JButton incLifeButton = new JButton("INCREASE LIFE");
        incLifeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                life.addLife(1);
            }
        });

        JButton decLifeButton = new JButton("DECREASE LIFE");
        decLifeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                life.subtractLife(1);
            }
        });

        JButton incDeathButton = new JButton("INCREASE DEATH");
        incDeathButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                death.addLife(1);
            }
        });

        JButton decDeathButton = new JButton("DECREASE DEATH");
        decDeathButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                death.subtractLife(1);
            }
        }); 

        buttonPanel.add(incLifeButton);
        buttonPanel.add(decLifeButton);
        buttonPanel.add(incDeathButton);
        buttonPanel.add(decDeathButton);

        frame.getContentPane().add(centerPanel, BorderLayout.CENTER);
        frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String\u005B\u005D args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new CustomPainting().createAndDisplayGUI();
            }
        });
    }
}

class RectangleComponent extends JComponent {

    private Color colour;
    private static final int MARGIN = 10;
    private int width;
    private int height;
    private int originalWidth;
    private RoundRectangle2D roundedRectangle;

    public RectangleComponent(Color c, int w, int h) {
        colour = c;
        width = w;
        height = h;
        originalWidth = width;
    }

    /*
     * Overriding this method, so that
     * the size of the JComponent
     * can be determined, on the screen
     * or by the LayoutManager concern.
     */
    @Override 
    public Dimension getPreferredSize() {
        return (new Dimension(width, height));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        roundedRectangle = new RoundRectangle2D.Float(MARGIN, MARGIN,
                                        width, height, MARGIN, MARGIN);
        g2d.setPaint(colour);
        g2d.draw(roundedRectangle);
        g2d.fill(roundedRectangle);
    }

    public void subtractLife(int amount) {
        width -= amount;
        System.out.println("ORIGINAL Width : " + originalWidth);
        System.out.println("Width : " + width);
        if (width > 0) {
            roundedRectangle.setRoundRect(MARGIN, MARGIN, width, height,
                                            MARGIN, MARGIN);
            /*
             * This repaint() will call the paintComponent(...)
             * by itself, so nothing else to be done.
             */
            repaint();
        } else {
            width += amount;
        }
    }

    public void addLife(int amount) {
        width += amount;
        System.out.println("ORIGINAL Width : " + originalWidth);
        System.out.println("Width : " + width);
        if (width < originalWidth) {
            roundedRectangle.setRoundRect(MARGIN, MARGIN, width, height,
                                            MARGIN, MARGIN);
            repaint();
        } else {
            width -= amount;
        }
    }
}

请问任何问题,当你通过这个程序时可能会出现这样的问题:-),我很乐意帮忙: - )

**两种颜色的最新编辑:**

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import javax.swing.*;

public class CustomPainting {

    private RectangleComponent lifeDeath;

    private void createAndDisplayGUI() {
        JFrame frame = new JFrame("Custom Painting");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel centerPanel = new JPanel();
        centerPanel.setLayout(new GridLayout(0, 2, 5, 5));
        // Specifying the WIDTH, HEIGHT and Colour for this JComponent.
        lifeDeath = new RectangleComponent(Color.GREEN, Color.RED, 20, 20);
        centerPanel.add(lifeDeath);

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridLayout(1, 2, 5, 5));
        JButton incLifeButton = new JButton("INCREASE LIFE");
        incLifeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                lifeDeath.addLife(1);
            }
        });

        JButton decLifeButton = new JButton("DECREASE LIFE");
        decLifeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                lifeDeath.subtractLife(1);
            }
        });

        buttonPanel.add(incLifeButton);
        buttonPanel.add(decLifeButton);

        frame.getContentPane().add(centerPanel, BorderLayout.CENTER);
        frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String\u005B\u005D args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new CustomPainting().createAndDisplayGUI();
            }
        });
    }
}

class RectangleComponent extends JComponent {

    private Color lifeColour;
    private Color deathColour;
    private static final int MARGIN = 10;
    private int widthLife;
    private int widthDeath;
    private int height;
    private int originalWidth;
    private RoundRectangle2D roundedRectangle;

    public RectangleComponent(Color lc, Color dc, int w, int h) {
        lifeColour = lc;
        deathColour = dc;
        widthLife = w;
        height = h;
        originalWidth = widthLife;
        widthDeath = 0;     
    }

    /*
     * Overriding this method, so that
     * the size of the JComponent
     * can be determined, on the screen
     * or by the LayoutManager concern.
     */
    @Override 
    public Dimension getPreferredSize() {
        return (new Dimension(originalWidth, height));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;

        roundedRectangle = new RoundRectangle2D.Float((MARGIN + widthDeath), MARGIN,
                                        widthLife, height, MARGIN, MARGIN);
        g2d.setPaint(lifeColour);
        g2d.draw(roundedRectangle);
        g2d.fill(roundedRectangle);

        roundedRectangle.setRoundRect(MARGIN, MARGIN,
                                        widthDeath, height, MARGIN, MARGIN);
        g2d.setPaint(deathColour);
        g2d.draw(roundedRectangle);
        g2d.fill(roundedRectangle);
    }

    public void subtractLife(int amount) {
        widthLife -= amount;
        widthDeath += amount;
        System.out.println("ORIGINAL Width : " + originalWidth);
        System.out.println("Width Life : " + widthLife);
        System.out.println("Width Death : " + widthDeath);
        if (widthLife > 0 && widthDeath < originalWidth) {
            /*
             * This repaint() will call the paintComponent(...)
             * by itself, so nothing else to be done.
             */
            repaint();
        } else {
            widthLife += amount;
            widthDeath -= amount;
        }
    }

    public void addLife(int amount) {
        widthLife += amount;
        widthDeath -= amount;
        System.out.println("ORIGINAL Width : " + originalWidth);
        System.out.println("Width Life : " + widthLife);
        System.out.println("Width Death : " + widthDeath);
        if (widthLife < originalWidth && widthDeath > 0) {
            repaint();
        } else {
            widthLife -= amount;
            widthDeath += amount;
        }   
    }
}