3

这是我当前的 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();
    }
}
4

3 回答 3

3

为了让您的 Swing 应用程序按预期工作,您需要牢记许多事情。由于您以错误的方式编码,因此总是必须遵循某些步骤才能避免可能出现的某些障碍。为此,请坚持 Swing Programming Strictly 的基础知识,并遵循它们。

  • 就像@HovercraftFullOfEels 提到的那样,您直接调用您的图形,这是永远不应该做的。

  • 其次,查看您的GameFrame()构造函数,将其设置为可见,甚至在您向其中添加任何组件之前以及在它的实际大小确定之前很久

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

现在来到你的程序,你错过了主要的事情,因为你没有指定你的CustomComponentie的大小JComponent,因此你无法在屏幕上看到它。当你将 a 扩展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;
        }   
    }
}
于 2012-04-20T07:36:16.767 回答
3

不需要传递给刚刚getJPanel的构造函数,也不需要手动调用。请参阅AWT 和 Swing 中的绘画。查看这个示例,该示例演示了一个绘制矩形的自定义组件。RectangleComponentGraphicspaintComponent

于 2012-04-20T02:52:52.940 回答
3

你的代码有点创意,有点疯狂,而且逻辑很难理解。最不寻常的方面是它有两个 JFrame,一个称为“帧”,一个是 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,并更好地组织您的代码。

于 2012-04-20T03:18:00.703 回答