【问题标题】:Why does calling dispose() on Graphics object cause JPanel to not render any components为什么在 Graphics 对象上调用 dispose() 会导致 JPanel 不呈现任何组件
【发布时间】:2012-12-04 09:44:57
【问题描述】:

在得知dispose() 应该在使用后在Graphics/Graphics2D 对象上调用后,我开始改变我的游戏以包含它。

当我在 JPanel 的覆盖 paintComponent(Graphics g) 中添加 g2d.dispose() 时,我添加的组件(JLabel 类的扩展)在未呈现的地方我仍然能够单击它们等,但它们不会是 画。

我用普通的JLabelJButton 进行了测试,效果相同(尽管JButton 在鼠标悬停时会呈现)。

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

这里有一个 SSCCE 来演示:

paintComponentMainMenuPanel 类中取消对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;
    }
}

【问题讨论】:

  • "在得知使用后应该在 Graphics/Graphics2D 对象上调用 dispose() 之后"你从哪里了解到的?
  • 对“哪里”也很感兴趣...
  • @kleopatra 这是对我的答案的评论,它与通过图形缩放图像有关,所以它是正确的,尽管我认为它是正确的,但无论何时使用图形对象都必须这样做
  • 感谢您的澄清 - 吸取的教训:不要相信每一条评论 :-)

标签: java swing graphics jpanel paintcomponent


【解决方案1】:

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

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

【讨论】:

  • +1 谢谢,我明白了我的错误,虽然每次我们使用paintComponent 等对象时都应该调用它,但我会在可以接受的时候接受
  • 我不明白您为什么说 您只需要在自己实际创建 Graphics 时处理它(例如通过调用 Component.getGraphics())。 当您打电话给Component.getGraphics() 你会创建一个新的Graphics 吗?我的理解是Graphics.createGraphics() 可以,但不是简单的getGraphics()。无论如何,我认为打电话给getGraphics() 通常是个坏主意,应该避免。
  • 您说得对,应该避免使用 getGraphics,但在文档中明确指出,这是获取 Graphics 上下文的一种方式。另外,getGraphics 文档说:创建一个图形上下文...,所以我假设每次都会创建一个新上下文。当然BufferedImage.createGraphics也是一种创建Graphics上下文的方式。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2010-09-18
    • 2011-12-16
    • 1970-01-01
    • 2013-02-11
    • 2014-05-01
    • 2023-03-04
    • 1970-01-01
    相关资源
    最近更新 更多