[英]Width and height of a JPanel are 0 (Specific Situation)
如果很難做到,請原諒我,但是我有一個特定的問題需要解決。 我已經做了很多研究,並且嘗試了許多解決方案,但是都沒有用。
我的問題是我有一個ImagePanel
類,它擴展了JPanel
(下面的代碼),該類需要使用寬度和高度來縮放圖像(我正在編寫一個程序,用戶可以在其中創建包括圖像的自定義教程)。 當我實例化它時,我得到一個錯誤,說寬度和高度必須為非零。 我知道這是因為布局管理器尚未將ImagePanel
傳遞給首選大小,但是我不知道如何將該大小傳遞給面板。 所述ImagePanel
是一個內部JPanel
其是內部JSplitPane
一個的內部JScrollPane
一個的內部JPanel
一個的內部JTabbedPane
一個的內部JSplitPane
一個的內部JFrame
。 容器順序遞減的圖形表示如下:
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
。
這不是一個好主意,因為縮放可能會花費一些時間,並且如果可以避免的話,您也不想拖慢繪制過程。
您可以使用附加到ImagePanel
的ComponentListener
並監視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.