簡體   English   中英

JPanel的寬度和高度為0(特定情況)

[英]Width and height of a JPanel are 0 (Specific Situation)

如果很難做到,請原諒我,但是我有一個特定的問題需要解決。 我已經做了很多研究,並且嘗試了許多解決方案,但是都沒有用。

我的問題是我有一個ImagePanel類,它擴展了JPanel (下面的代碼),該類需要使用寬度和高度來縮放圖像(我正在編寫一個程序,用戶可以在其中創建包括圖像的自定義教程)。 當我實例化它時,我得到一個錯誤,說寬度和高度必須為非零。 我知道這是因為布局管理器尚未將ImagePanel傳遞給首選大小,但是我不知道如何將該大小傳遞給面板。 所述ImagePanel是一個內部JPanel其是內部JSplitPane一個的內部JScrollPane一個的內部JPanel一個的內部JTabbedPane一個的內部JSplitPane一個的內部JFrame 容器順序遞減的圖形表示如下:

  1. JFrame(GridLayout)
  2. JSplitPane(默認SplitPane布局)
  3. JTabbedPane(Deault JTabbedPane布局)
  4. JPanel(GridLayout)
  5. JScrollPane(默認ScrollPane布局)
  6. JSplitPane(默認SplitPane布局)
  7. JPanel(GridLayout);
  8. 圖像面板

ImagePanel的代碼如下:

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class ImagePanel extends JPanel{

    private BufferedImage i;
    private ImageIcon miniature;
    private Image paint = null;

    public void createImage(String path){
        try {                
            i = ImageIO.read(new File(path));
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        if(i != null){
            int width = (int)((double)i.getWidth() * ((double)getWidth()/i.getWidth()));
            int height = (int)((double)i.getHeight()*i.getHeight()/i.getWidth()*((double)this.getHeight()/i.getHeight()));
            miniature = new ImageIcon(i.getScaledInstance(width, height, Image.SCALE_SMOOTH));
            paint = miniature.getImage();
        }

    }


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

        if (paint!=null){
            g.drawImage(paint, 0, 0, null);}     
    }

}

如何獲得合適的ImagePanel大小。 我希望圖像隨着JFrame的大小而改變大小,這就是為什么我不只是使用setPreferedSize();

我希望圖像隨着JFrame的大小而改變

可以使用Darryl的Stretch Icon而不是在您自己的組件中進行自定義繪制。 圖標將根據可用空間自動調整大小。

這就是為什么我不只是使用'setPreferedSize();'的原因。

如果您確實使用自定義繪畫,則不應使用setPreferredSize()。 您應該重寫getPreferredSize()方法以返回圖像的大小。 請記住,首選大小僅是布局管理器的建議。 布局管理器可以使用或忽略大小。

如果要在paintComponent()方法中自動縮放圖像,則代碼應為:

Dimension d = getSize();
g.drawImage(paint, 0, 0, d.width, d.height, this);

因此,代碼(無論選擇哪種解決方案)中的真正挑戰是,確保使用的布局管理器將為組件提供所有可用空間,以便可以自動縮放圖像。

至少有兩種方法可以實現,第一種是允許paintComponent檢查paint的狀態並在圖像為null時適當地重新縮放圖像。

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

    if (i != null && paint == null){
        generateScaledInstance();
    }
    if (paint != null) {
        g.drawImage(paint, 0, 0, this);
    }
}

這將起作用,因為除非組件的大小大於0且已附加到本地對等點(在屏幕上),否則絕對不應調用paintComponent

這不是一個好主意,因為縮放可能會花費一些時間,並且如果可以避免的話,您也不想拖慢繪制過程。

您可以使用附加到ImagePanelComponentListener並監視componentResized事件

addComponentListener(new ComponentAdapter() {
    @Override
    public void componentResized(ComponentEvent e) {
        if (i != null) {
            generateScaledInstance();
        }
    }
});

這可能會連續多次被調用,所以要小心。

在這種情況下,我傾向於使用設置為小延遲的javax.swing.Timer將更新合並到盡可能少的調用,例如。

private Timer resizeTimer;
//...
// Probably in you classes constructor
resizeTimer = new Timer(250, new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        // Actually perform the resizing of the image...
        generateScaledInstance();
    }
});
// Don't want a repeating event...
resizeTimer.setRepeats(false);

//...
public void componentResized(ComponentEvent evt) {
    resizeTimer.restart();
}

這允許快速連續調用componentResized多次,但是例如,如果兩次間隔之間的時間超過250毫秒,則可以調用generateScaledInstance ...

還應該提供一種preferredSize非的值0大小默認(記住,一個面板的默認大小優選是0x0 )。 取決於布局管理器,這可以忽略,但是通常用作大多數布局管理器的基礎...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM