2014-01-15 28 views
5

問:調用調用setVisible(真)已經可見幀

什麼叫調用setVisible(真)在JFrame這已經是可見的嗎?我正在挖掘JFrame的源代碼,最終它歸結爲this function in Component,如果它已經可見,它對幀沒有任何作用。它爲什麼像revalidate(); repaint();? (參見SSCCE下文)


動機:

我正在一個Java應用程序,爲此,我寫了一類JImagePanel延伸JPanel和允許用戶將圖像設置爲背景(見SSCCE)。我發現在編輯面板的背景之後,我有問題將背景重繪爲正確的大小。在網上淘之後,我發現了以下工作:

if(frame.isVisible()) frame.setVisible(true); 

最終,我解決了使用

panel.revalidate(); 
panel.repaint(); 

,我認爲這是更好的解決方案的問題,但它讓我想什麼setVisible(true)實際上是在一個已經可見的框架上做的從我的觀點來看,它不應該起作用 - 但實際上它確實如此。


SSCCE

這裏是說明我的問題的例子。如果沒有別的,希望你會發現這個類在將來非常有用。

備註:該文件的更新源文件可在項目主頁GitHub上找到。

享受!

package com.dberm22.utils; 

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Image; 
import java.awt.RenderingHints; 
import java.awt.Toolkit; 
import java.awt.image.BufferedImage; 

import javax.swing.ImageIcon; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class JImagePanel extends JPanel { 

    private static final long serialVersionUID = 6841876236948317038L; 
    private Image img = null; 
    private Position position = Position.CENTER; 

    public enum Position{ 
     STRETCH, 
     CENTER, 
     FIT, 
     FILL, 
     NONE; 
    } 

    public JImagePanel() { 
     } 

    public JImagePanel(String img) { 
    this(new ImageIcon(img).getImage()); 
    } 

    public JImagePanel(Image img) { 

     setBackgroundImage(img); 
    } 

    @Override 
    public void paintComponent(Graphics g) 
    { 
    super.paintComponent(g); 

    Graphics2D g2 = (Graphics2D) g; 

    g2.setColor(getBackground()); 
    g2.fillRect(0, 0, getWidth(), getHeight()); 

    if (this.position.equals(Position.STRETCH)) 
    { 
     if(this.img != null) g2.drawImage(img, 0, 0, getWidth(), getHeight(), null); 
    } 
    else if (this.position.equals(Position.FILL) || this.position.equals(Position.FIT)) 
    { 
     if(this.img != null) 
     { 

      double scaleFactor = getScaleFactor(new Dimension(img.getWidth(null), img.getHeight(null)), getSize()); 
      int scaleWidth = (int) Math.round(img.getWidth(null) * scaleFactor); 
      int scaleHeight = (int) Math.round(img.getHeight(null) * scaleFactor); 

      //Image img_scaled = img.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH); 
      g2.drawImage(scaleImage(img, scaleWidth, scaleHeight, getBackground()), (getWidth() - scaleWidth)/2, (getHeight() - scaleHeight)/2, scaleWidth, scaleHeight, null); 
     } 
    } 
    else if (this.position.equals(Position.CENTER)) { if(this.img != null) g2.drawImage(img, (getWidth() - img.getWidth(null))/2, (getHeight() - img.getHeight(null))/2, null); } 
    } 

    public void setBackgroundImage(String img) 
    { 
     setBackgroundImage(new ImageIcon(img).getImage()); 
    } 

    public void setBackgroundImage(Image img) 
    { 
     this.img = img; 
     Dimension size = new Dimension(img.getWidth(null), img.getHeight(null)); 
     setPreferredSize(size); 
     setMinimumSize(size); 
     setMaximumSize(size); 
     setSize(size); 

     repaint(); 
    } 

    public static double getScaleFactor(int iMasterSize, int iTargetSize) { 

     double dScale = 1; 
     if (iMasterSize > iTargetSize) { 

      dScale = (double) iTargetSize/(double) iMasterSize; 

     } else { 

      dScale = (double) iTargetSize/(double) iMasterSize; 

     } 

     return dScale; 

    } 

    public double getScaleFactor(Dimension original, Dimension targetSize) { 

     double dScale = 1d; 

     if (original != null && targetSize != null) { 

      double dScaleWidth = getScaleFactor(original.width, targetSize.width); 
      double dScaleHeight = getScaleFactor(original.height, targetSize.height); 

      if (this.position.equals(Position.FIT)) dScale = Math.min(dScaleHeight, dScaleWidth); 
      else if(this.position.equals(Position.FILL)) dScale = Math.max(dScaleHeight, dScaleWidth); 

     } 

     return dScale; 

    } 

    public BufferedImage scaleImage(Image img, int width, int height, Color background) { 

     BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
     Graphics2D g = newImage.createGraphics(); 
     try { 
      g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
        RenderingHints.VALUE_INTERPOLATION_BICUBIC); 
      g.setBackground(background); 
      g.clearRect(0, 0, width, height); 
      g.drawImage(img, 0, 0, width, height, null); 
     } finally { 
      g.dispose(); 
     } 
     return newImage; 
    } 

    public void setBackgroundImagePosition(String pos) 
    { 
     if("Stretch".equals(pos)) setBackgroundImagePosition(Position.STRETCH); 
     else if("Center".equals(pos)) setBackgroundImagePosition(Position.CENTER); 
     else if("Fit".equals(pos)) setBackgroundImagePosition(Position.FIT); 
     else if("Fill".equals(pos)) setBackgroundImagePosition(Position.FILL); 
     else if("None".equals(pos)) setBackgroundImagePosition(Position.NONE); 
    } 
    public void setBackgroundImagePosition(Position pos) 
    { 
     this.position = pos; 
     repaint(); 
    } 

    public static void main(String[] args) 
    { 

     JFrame frame = new JFrame("JImagePanel Test"); 
     frame.setSize(Toolkit.getDefaultToolkit().getScreenSize()); 
     frame.setPreferredSize(Toolkit.getDefaultToolkit().getScreenSize()); 
     frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //sets appropriate size for frame 

     JImagePanel panel = new JImagePanel(); 
     frame.add(panel); 

     frame.setVisible(true); 

     try {Thread.sleep(2000);} catch (InterruptedException e) {} 

     panel.setBackgroundImage("C:\\Users\\David\\Pictures\\Wood.jpg"); 
     panel.setBackgroundImagePosition(JImagePanel.Position.STRETCH); 

     panel.revalidate(); // need to revalidate() 
     panel.repaint(); //doesnt work by itself 

     try {Thread.sleep(2000);} catch (InterruptedException e) {} 

     panel.setBackgroundImage("C:\\Users\\David\\Pictures\\Wood.jpg"); 
     panel.setBackgroundImagePosition(JImagePanel.Position.FIT); 

     frame.setVisible(true); //also works --why? 

    } 

} 
+2

爲什麼需要重繪面板?你添加了一個新組件還是有另一個原因?發佈[SSCCE](http://sscce.org/)將有很大幫助。 –

+0

我確定從JFrame重新驗證()&repaint()刷新所有JComponents樹,肯定有一個潛在的問題重新關閉,可以關閉,以編程方式爲JComponents – mKorbel

+2

這完全是史前AWT問題,請確保檢查第三方代碼,如果不是基於AWT容器,那麼你必須重新繪製這個容器(例如,reDraw()必須以良好的代碼實現) – mKorbel

回答

2

調用上JFrame這已經是對你可見的作品,因爲這最終調用validate()內部,進而重新驗證幀中所有子setVisible(true)

要知道爲什麼,請參閱的Component.setVisible(boolean b)實現:

public void setVisible(boolean b) { 
    show(b); 
} 

public void show(boolean b) { 
    if (b) { 
     show(); 
    } else { 
     hide(); 
    } 
} 

show()方法在Window重寫(其中JFrame的是一個子類)。所以這最終致電Window.show()

public void show() { 
    if (peer == null) { 
     addNotify(); 
    } 
    validate(); 
    [...] 

希望這可以解釋你所看到的行爲。

+0

+1挖掘:-) – kleopatra

+0

啊,窗口子類重寫show()。我錯過了 - 謝謝。 – dberm22

2

假設你是一箇中途乾淨實現你的imagePanel後:

  • 讓面板做了自己的再確認/ -paint如需要(與應用程序代碼)
  • do not call setXXSize,永遠,甚至沒有在面板內部

這是改變你的setter和重寫getXXSize。需要注意的是立足於單獨的圖像尺寸大小的提示是你想在現實世界中的代碼做什麼,你可能要採取超的提示考慮以及(FI如果面板上有孩子)

@Override 
public Dimension getPreferredSize() { 
    if (img != null) { 
     return new Dimension(img.getWidth(this), img.getHeight(this)); 
    } 
    return super.getPreferredSize(); 
} 

public void setBackgroundImage(Image img) { 
    this.img = img; 
    // need to revalidate as our sizing hints might have changed 
    revalidate(); 
    repaint(); 
} 

public void setBackgroundImagePosition(Position pos) { 
    this.position = pos; 
    repaint(); 
} 
現在使用它只是

應用程序代碼調用的制定者,沒有別的:

JFrame frame = new JFrame("JImagePanel Test"); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    // frame.setLayout(new FlowLayout()); // just to see the effect of a pref-respecting layout 
    final JImagePanel panel = new JImagePanel(); 
    frame.add(panel); 

    final Image[] images = new Image[]{ 
      XTestUtils.loadDefaultImage(), XTestUtils.loadDefaultImage("500by500.png"), null}; 
    Action toggleImage = new AbstractAction("toggle image") { 
     int index = 0; 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      panel.setBackgroundImage(images[index]); 
      index = (index +1) % images.length; 
     } 
    }; 
    Action togglePosition = new AbstractAction("toggle position") { 
     int index = 0; 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      panel.setBackgroundImagePosition(Position.values()[index]); 
      index = (index +1) % Position.values().length; 
     } 
    }; 
    frame.add(new JButton(toggleImage), BorderLayout.NORTH); 
    frame.add(new JButton(togglePosition), BorderLayout.SOUTH); 
    // size for frame 
    //frame.setSize(800, 800); 
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //sets appropriate 
    frame.setVisible(true); 
+0

這不會回答這個問題(請參閱Grodriguez),但在內部調用revalidate()對我應該(並且將會)製作的課程絕對是一個改進。併爲擴展測試用例+1。感謝您的意見。 – dberm22

+0

這確實是正確的做法。 – Grodriguez

相關問題