2012-12-17 13 views
6

Dopo aver appreso che dispose() deve essere richiamato su Graphics/Graphics2D oggetto dopo l'uso, sono andato a modificare il mio gioco per incorporarlo.Perché la chiamata dispose() sull'oggetto Graphics causa a JPanel di non eseguire il rendering di alcun componente

Quando ho aggiunto g2d.dispose() in override paintComponent(Graphics g) di JPanel, miei componenti che ho aggiunto (estensioni di JLabel classe) dove non fusi sono stato in grado di fare clic ancora su di loro, ecc, ma non sarebbe dipinto.

Ho eseguito il test con un normale JLabel e JButton con lo stesso effetto (anche se JButton viene visualizzato quando il mouse lo supera).

Quindi la mia domanda è: perché succede?

Ecco uno SSCCE dimostrare:

enter image description here

dopo la chiamata decommentando a dispose() in paintComponent di MainMenuPanel classe:

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

"Dopo aver appreso che dispose() deve essere chiamato su oggetto Graphics/Graphics2D dopo l'uso" Dove l'hai imparato? – msell

+0

interessato al "dove" ... – kleopatra

+0

@kleopatra Era un commento su una mia risposta, aveva a che fare con il ridimensionamento di un'immagine tramite la grafica, quindi era corretto anche se l'ho preso, dobbiamo farlo quando si lavora con oggetti grafici –

risposta

20

Il fatto è che il Graphics contesto stai usando in paintComponent viene creato e fornito dal chiamante (il framework), che è anche responsabile del suo smaltimento.

È necessario smaltire lo Graphics solo quando lo si crea effettivamente (ad esempio chiamando Component.getGraphics()). Nel tuo caso, non lo stai creando, lo stai semplicemente trasmettendo, quindi in questo caso non chiamare .

+0

+1 grazie vedo il mio errore, io però dovrebbe essere chiamato ogni volta che usiamo l'oggetto come in paintComponent ecc. accetterà quando can –

+2

Non capisco perché tu dichiari _È sufficiente disporre di Graphics quando lo crei tu stesso (ad esempio chiamando Component.getGraphics()) ._ Quando chiami 'Component.getGraphics()' crei un nuovo 'Graphics'? La mia comprensione era che 'Graphics.createGraphics()' funziona, ma non un semplice 'getGraphics()'. E comunque, credo che chiamare 'getGraphics()' sia di solito una cattiva idea e dovrebbe essere evitato. –

+0

Hai ragione che 'getGraphics' dovrebbe essere evitato, ma è esplicitamente dichiarato nei documenti come un modo per ottenere un contesto' Graphics'. Inoltre, la documentazione di 'getGraphics' dice: * Crea un contesto grafico ... *, quindi presumo che venga creato un nuovo ogni volta. Naturalmente, 'BufferedImage.createGraphics' è anche un modo per creare un contesto' Graphics'. –

3

Perché .dispose() rilascia le risorse. Sì, tutto.

+0

+1 grazie per la risposta –