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

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

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

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

  • 其次,看看你的GameFrame()构造函数,你将它设置为可见,甚至在你向它添加任何组件之前,甚至在它的实际大小已经建立之前

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

现在进入你的程序,你错过了主要的东西,因为你没有指定你的CustomComponentJComponent的大小,因此你无法在屏幕上看到它。 当你将JCompoent扩展到你的类时,使它成为习惯的habbit来覆盖它的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; } } } 

不需要将JPanel传递给RectangleComponent的构造函数只是为了获取Graphics ,而不需要手动调用paintComponent 。 请参阅AWT和Swing中的绘画 。 查看此示例 ,演示绘制矩形的自定义组件。

你的代码有点创意,有点疯狂,并且逻辑非常难以理解。 最不寻常的方面是它有两个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,并更好地组织你的代码。