java 为什么在 Graphics 对象上调用 dispose() 会导致 JPanel 不渲染任何组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13911743/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 14:25:05  来源:igfitidea点击:

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

javaswinggraphicsjpanelpaintcomponent

提问by David Kroukamp

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

在了解到dispose()应该在使用后调用Graphics/Graphics2D对象后,我开始更改我的游戏以合并它。

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

当我添加g2d.dispose()覆盖paintComponent(Graphics g)JPanel,我添加的组件(JLabel类的扩展)未呈现时,我仍然可以单击它们等,但它们不会被绘制

I tested with a normal JLabeland JButtonwith same effect (though JButtonis rendered when mouse is over it).

我用正常JLabelJButton相同的效果进行了测试(尽管JButton当鼠标悬停在它上面时会呈现)。

So my question is why does this happen?

所以我的问题是为什么会发生这种情况?

Here is an SSCCE to demonstrate:

这是一个 SSCCE 来演示:

enter image description here

在此处输入图片说明

after uncommenting call to dispose()in paintComponentof MainMenuPanelclass:

在取消对dispose()in paintComponentof MainMenuPanelclass 的调用后:

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

回答by Thorsten Dittmar

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

问题是Graphics你正在使用的上下文paintComponent是由调用者(框架)创建和提供的,它也负责处理它。

You only need to dispose of Graphicswhen 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 disposein this case.

您只需要Graphics在您自己实际创建它时处理它(例如通过调用Component.getGraphics())。在你的情况下,你不是在创建它,你只是在投射它,所以在这种情况下不要调用 dispose

回答by Michael 'Maik' Ardan

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

因为.dispose()释放你的资源。是的,一切。