Do I actually call the paintComponent method I make when creating a rectangle in Java?

孤人 提交于 2019-12-02 00:04:11

问题


This is my current RectangleComponent class and I add it to a panel in my main JFrame but it never appears. I thought it wasn't drawing so I decided to call the paintComponent method in the Rectangle's constructor, and after sorting through 4-5 nullPointerExceptions, nothing has changed. I've read multiple guides on how to draw rectangles and I have seen multiple code examples, but I can never get the panels to work with more than one JComponent. If you could, please take a brief look at my code and see if you can devise a solution. Thank you for your time. Also listed is the Frame I call the rectangle constructor in.

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();
    }
}

回答1:


In order for your Swing Application to work as expected, there are many a things you need to keep in mind. There are always certain steps that one must follow in order to escape certain hurdles, that might can arise, since you coded in the wrong way. For this stick to the basics of Swing Programming Strictly, and follow them.

  • Like as mentioned by @HovercraftFullOfEels , you calling to your Graphics directly, which one should never do.

  • Secondly, look at your GameFrame() constructor, you set it to visible, even before you had added any components to it and much before it's real size has been established

Such loop holes inside your coding might can give rise to many a headaches, as you sit down to write huge programs, so better to be on the safe road from the beginning, then to curse yourself at the later stage. As they say Prevention is better than Cure.

Now coming to your program, you missed the main thingy, since you failed to specify the size of your CustomComponent i.e. JComponent, hence you are not been able to see it on your screen. As you extends a JCompoent to your class, make it a customary habbit to override it's getPreferredSize(), in the same manner you override it's paintComponent(...) method.

Have a look at this small program, I had crafted for you, might be this be able to help you out, to understand the logic a bit more.

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;
        }
    }
}

Do ask any question, that might can arise as you go through this program :-), I be HAPPY to help on that :-)

**LATEST EDIT WITH TWO COLOURS : **

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;
        }   
    }
}



回答2:


No need to pass JPanel to the constructor of RectangleComponent just to get Graphics, and no need to manually call paintComponent. See Painting in AWT and Swing. Check out this example that demonstrates a custom component that paints a rectangle.




回答3:


Your code is a bit creative, a bit crazy, and with logic that is very hard to follow. The most unusual aspect is that it has two JFrames, one called "frame", and one the GameFrame object itself, both of which get components added, but only one of which shows. You also have many methods that return void (which if over-used increases code smell) and only add to making the code more confusing.

For example,

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???
}

This is all very confusing, and not likely going to work.

Then there's your trying to call paintComponent directly and calling getGraphics on a JComponent, both of which should not be done. You will want to go through the graphics tutorials to see how to do this correctly.

I recommend that you consider re-writing this, and first and foremost, using only one JFrame, and organizing your code better.



来源:https://stackoverflow.com/questions/10239430/do-i-actually-call-the-paintcomponent-method-i-make-when-creating-a-rectangle-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!