Why does calling dispose() on Graphics object cause JPanel to not render any components

17,654

Solution 1

The thing is that the Graphics context you are using in paintComponent is created and provided by the caller (the framework), which is also responsible for disposing of it.

You only need to dispose of Graphics when you actually create it yourself (for example by calling Component.getGraphics()). In your case, you're not creating it, you're just casting it, so do not call dispose in this case.

Solution 2

Because .dispose() releases your resources. Yes, everything.

Share:
17,654
David Kroukamp
Author by

David Kroukamp

Note worthy Badges: 10th user to be awarded Gold Badge for swing (1st in South Africa) 140th user to be awarded Gold Badge for java (2nd in South Africa) 7th user to be awarded Silver Badge for jpanel 7th user to be awarded Bronze Badge for jframe 5th user to be awarded Bronze Badge for paintcomponent Featured Poster @ Daniweb View David Kroukamp's profile on LinkedIn My dream is to write kernel drivers, create my own Anti-Virus... Oh and my own Operating System. I am also interested in creating games, hacking, virus writing and malware analysis and reverse engineering - for educational purposes only though.

Updated on July 22, 2022

Comments

  • David Kroukamp
    David Kroukamp almost 2 years

    After learning that dispose() should be called on Graphics/Graphics2D object after use, I went about changing my game to incorporate this.

    When I added g2d.dispose() in overridden paintComponent(Graphics g) of JPanel, my components which I added (extensions of JLabel class) where not rendered I was able to still click on them etc but they would not be painted.

    I tested with a normal JLabel and JButton with same effect (though JButton is rendered when mouse is over it).

    So my question is why does this happen?

    Here is an SSCCE to demonstrate:

    enter image description here

    after uncommenting call to dispose() in paintComponent of MainMenuPanel class:

    enter image description here

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Image;
    import java.awt.RenderingHints;
    import java.awt.event.FocusAdapter;
    import java.awt.event.FocusEvent;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.image.BufferedImage;
    import java.net.URL;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.imageio.ImageIO;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class Test {
    
        public Test() {
            try {
                initComponents();
            } catch (Exception ex) {
                Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Test();
                }
            });
        }
    
        private void initComponents() throws Exception {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setResizable(false);
    
            MainMenuPanel mmp = new MainMenuPanel();
            frame.add(mmp);
    
            frame.pack();
            frame.setVisible(true);
        }
    }
    
    class MainMenuPanel extends JPanel {
    
        //create labels for Main Menu
        private PopUpJLabel versusesModeLabel;
        private PopUpJLabel singlePlayerModeLabel;
        private PopUpJLabel optionsLabel;
        private PopUpJLabel helpLabel;
        private PopUpJLabel aboutLabel;
        //create variable to hold background
        private Image background;
        private Dimension preferredDimensions;
        public static String gameType;
        public static final String SINGLE_PLAYER = "Single Player", VERSUS_MODE = "VS Mode";
    
        /**
         * Default constructor to initialize double buffered JPanel with
         * GridBagLayout
         */
        public MainMenuPanel() {
            super(new GridBagLayout(), true);
            try {
                initComponents();
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(null, "Could not load main menu background!", "Main Menu Error: 0x004", JOptionPane.ERROR_MESSAGE);
                System.exit(4);
            }
        }
    
        /*
         * Create JPanel and its components
         */
        private void initComponents() throws Exception {
    
            //set prefered size of JPanel
            preferredDimensions = new Dimension(800, 600);
    
            background = scaleImage(800, 600, ImageIO.read(new URL("http://photos.appleinsider.com/12.08.30-Java.jpg")));
    
            //create label instances
            singlePlayerModeLabel = new PopUpJLabel("Single Player Mode");
            singlePlayerModeLabel.setEnabled(false);
    
            versusesModeLabel = new PopUpJLabel("Versus Mode");
            optionsLabel = new PopUpJLabel("Options");
            helpLabel = new PopUpJLabel("Help");
            aboutLabel = new PopUpJLabel("About");
    
            //create new constraints for gridbag
            GridBagConstraints gc = new GridBagConstraints();
            gc.fill = GridBagConstraints.HORIZONTAL;
            gc.ipady = 50;//vertical spacing 
    
            //add newGameLabel to panel with constraints
            gc.gridx = 0;
            gc.gridy = 0;
            add(singlePlayerModeLabel, gc);
    
            gc.gridy = 1;
            add(versusesModeLabel, gc);
            //add optionsLabel to panel with constraints (x is the same)
            gc.gridy = 2;
            add(optionsLabel, gc);
            //add helpLabel to panel with constraints (x is the same)
            gc.gridy = 3;
            add(helpLabel, gc);
            //add aboutLabel to panel with constraints (x is the same)
            gc.gridy = 4;
            add(aboutLabel, gc);
        }
    
        public static BufferedImage scaleImage(int w, int h, BufferedImage img) throws Exception {
            BufferedImage bi;
            //bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            bi = new BufferedImage(w, h, img.getType());
            Graphics2D g2d = (Graphics2D) bi.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
            g2d.drawImage(img, 0, 0, w, h, null);
            g2d.dispose();
            return bi;
        }
    
        /*
         * Will return the preffered size of JPanel
         */
        @Override
        public Dimension getPreferredSize() {
            return preferredDimensions;
        }
    
        /*
         * Will draw the background to JPanel with anti-aliasing on and quality rendering
         */
        @Override
        protected void paintComponent(Graphics grphcs) {
            super.paintComponent(grphcs);
    
            //convert graphics object to graphics2d object
            Graphics2D g2d = (Graphics2D) grphcs;
    
            //set anti-aliasing on and rendering etc
            //GamePanel.applyRenderHints(g2d);
    
            //draw the image as the background
            g2d.drawImage(background, 0, 0, null);
    
            //g2d.dispose();//if I uncomment this no LAbels will be shown
        }
    }
    
    class PopUpJLabel extends JLabel {
    
        public final static Font defaultFont = new Font("Arial", Font.PLAIN, 50);
        public final static Font hoverFont = new Font("Arial", Font.BOLD, 70);
    
        PopUpJLabel(String text) {
            super(text);
            setHorizontalAlignment(JLabel.CENTER);
            setForeground(Color.ORANGE);
            setFont(defaultFont);
    
            //allow component to be focusable
            setFocusable(true);
    
            //add focus adapter to change fints when focus is gained or lost (used for transversing labels with keys)
            addFocusListener(new FocusAdapter() {
                @Override
                public void focusGained(FocusEvent fe) {
                    super.focusGained(fe);
                    if (isEnabled()) {
                        setFont(getHoverFont());
                    }
                }
    
                @Override
                public void focusLost(FocusEvent fe) {
                    super.focusLost(fe);
                    setFont(getDefaultFont());
                }
            });
    
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseEntered(MouseEvent me) {
                    super.mouseEntered(me);
                    if (isEnabled()) {
                        setFont(getHoverFont());
                    }
                    //call for focus mouse is over this component
                    requestFocusInWindow();
                }
            });
    
        }
    
        Font getDefaultFont() {
            return defaultFont;
        }
    
        Font getHoverFont() {
            return hoverFont;
        }
    }
    
  • David Kroukamp
    David Kroukamp over 11 years
    +1 thank you i see my mistake I though it should be called every time we use the object like in paintComponent etc. will accept when I can
  • Guillaume Polet
    Guillaume Polet over 11 years
    I don't understand why you state You only need to dispose of Graphics when you actually create it yourself (for example by calling Component.getGraphics()). When you call Component.getGraphics() do you create a new Graphics? My understanding was that Graphics.createGraphics() does, but not a simple getGraphics(). And anyway, I believe that calling getGraphics() is usually a bad idea and should be avoided.
  • Thorsten Dittmar
    Thorsten Dittmar over 11 years
    You are right that getGraphics should be avoided, but it is explicitly stated in the docs as a way to obtain a Graphics context. Also, getGraphics documentation say: Creates a Graphics context..., so I assume that a new one is created every time. Of course, BufferedImage.createGraphics is also a way to create a Graphics context.