Java 为什么对图形对象调用dispose()会导致JPanel不呈现任何组件

Java 为什么对图形对象调用dispose()会导致JPanel不呈现任何组件,java,swing,graphics,jpanel,paintcomponent,Java,Swing,Graphics,Jpanel,Paintcomponent,在了解到使用后应在Graphics/Graphics2D对象上调用dispose()后,我开始更改游戏以合并此功能 当我在JPanel的重写paintComponent(Graphics g)中添加g2d.dispose()时,我添加的组件(JLabel类的扩展)在未渲染的地方仍然可以单击它们,但它们不会被绘制 我用一个正常的JLabel和JButton进行了测试,效果相同(尽管当鼠标在JButton上时会呈现) 所以我的问题是为什么会发生这种情况 以下是一个SSCCE演示: 取消对MainM

在了解到使用后应在
Graphics
/
Graphics2D
对象上调用
dispose()
后,我开始更改游戏以合并此功能

当我在
JPanel
的重写
paintComponent(Graphics g)
中添加
g2d.dispose()
时,我添加的组件(JLabel类的扩展)在未渲染的地方仍然可以单击它们,但它们不会被绘制

我用一个正常的
JLabel
JButton
进行了测试,效果相同(尽管当鼠标在
JButton
上时会呈现)

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

以下是一个SSCCE演示:

取消对
MainMenuPanel
class的
paintComponent
中的
dispose()
调用的注释后:

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


问题是,您在
paintComponent
中使用的
图形
上下文是由调用方(框架)创建和提供的,调用方还负责处理它


您只需要在自己实际创建图形时(例如,通过调用
Component.getGraphics()
)处理图形。在您的情况下,您不是在创建它,您只是在强制转换它,所以在这种情况下不要调用dispose。

因为
.dispose()
释放了您的资源。是的,所有内容。

“在了解使用后应在Graphics/Graphics2D对象上调用dispose()后”您从哪里了解到的?对“Where”也感兴趣…@kleopatra这是对我的答案的评论,它与通过图形缩放图像有关,因此它是正确的,尽管我接受了它,但无论何时使用图形对象,我们都必须这样做感谢澄清-学到的教训:不要相信所有评论:-)+1谢谢你,我看到了我的错误,我想每次使用对象时都应该调用它,如在paintComponent等。当我canI不明白为什么您声明您只需要在自己实际创建图形时处理图形(例如,通过调用Component.getGraphics())。调用
Component.getGraphics()
时,是否创建新的
Graphics
?我的理解是,
Graphics.createGraphics()
可以,但不是简单的
getGraphics()
。无论如何,我认为调用
getGraphics()
通常是一个坏主意,应该避免。你说得对,应该避免调用
getGraphics
,但文档中明确说明了这是获取
Graphics
上下文的一种方式。另外,
getGraphics
文档说:创建一个图形上下文…,所以我假设每次都会创建一个新的上下文。当然,
buffereImage.createGraphics
也是创建
Graphics
上下文的一种方法。