[英]Width and height of a JPanel are 0 (Specific Situation)
Please pardon me if this is hard to follow, but I have a specific problem that I need help solving. 如果很难做到,请原谅我,但是我有一个特定的问题需要解决。 I have done a ton of research, and I have tried numerous solutions but none of them are working.
我已经做了很多研究,并且尝试了许多解决方案,但是都没有用。
My issue is that I have an ImagePanel
class that is extending JPanel
(code below), this class needs to use width and height to scale images (I am making a program where users can create custom tutorials including images). 我的问题是我有一个
ImagePanel
类,它扩展了JPanel
(下面的代码),该类需要使用宽度和高度来缩放图像(我正在编写一个程序,用户可以在其中创建包括图像的自定义教程)。 When I instantiate this I get an error saying that the width and height must be nonzero. 当我实例化它时,我得到一个错误,说宽度和高度必须为非零。 I understand that this is because the layout manager has not yet passed the
ImagePanel
a preferred size, however I do not know how to get that size to the panel. 我知道这是因为布局管理器尚未将
ImagePanel
传递给首选大小,但是我不知道如何将该大小传递给面板。 The ImagePanel
is inside a JPanel
which is inside a JSplitPane
inside of a JScrollPane
inside of a JPanel
inside of a JTabbedPane
inside of a JSplitPane
inside of a JFrame
. 所述
ImagePanel
是一个内部JPanel
其是内部JSplitPane
一个的内部JScrollPane
一个的内部JPanel
一个的内部JTabbedPane
一个的内部JSplitPane
一个的内部JFrame
。 A graphical representation of this in decreasing container order is as follows: 容器顺序递减的图形表示如下:
The code for the ImagePanel is as follows: 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);}
}
}
How can I get the proper size to the ImagePanel
. 如何获得合适的
ImagePanel
大小。 I would like the image to change size with the size of the JFrame
, which is why I don't just use setPreferedSize();
我希望图像随着
JFrame
的大小而改变大小,这就是为什么我不只是使用setPreferedSize();
. 。
I would like the image to change size with the size of the JFrame
我希望图像随着JFrame的大小而改变
Instead of doing custom painting in your own component you can use Darryl's Stretch Icon . 可以使用Darryl的Stretch Icon而不是在您自己的组件中进行自定义绘制。 The Icon will automatically be resized based on the space available.
图标将根据可用空间自动调整大小。
which is why I dont just use 'setPreferedSize();'.
这就是为什么我不只是使用'setPreferedSize();'的原因。
If you do use custom painting then you should NOT use setPreferredSize(). 如果您确实使用自定义绘画,则不应使用setPreferredSize()。 You SHOULD be overriding the
getPreferredSize()
method to return the size of the image. 您应该重写
getPreferredSize()
方法以返回图像的大小。 Remember the preferred size is just a suggestion to the layout manager. 请记住,首选大小仅是布局管理器的建议。 The layout manager can use or ignore the size.
布局管理器可以使用或忽略大小。
If you want to scale the image automatically in your paintComponent() method then the code should be: 如果要在paintComponent()方法中自动缩放图像,则代码应为:
Dimension d = getSize();
g.drawImage(paint, 0, 0, d.width, d.height, this);
So the real challenge in your code (no matter which solution you choose) is to make sure you are using a layout manger that will give all available space to your component so the image can be scaled automatically. 因此,代码(无论选择哪种解决方案)中的真正挑战是,确保使用的布局管理器将为组件提供所有可用空间,以便可以自动缩放图像。
There are at least two ways this might be achieved, the first would be to allow the paintComponent
to check the state of the paint
and rescale the image appropriatly when it is null
至少有两种方法可以实现,第一种是允许
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);
}
}
This will work because paintComponent
should never be called unless the component has a size greater than 0
and is attached to a native peer (on the screen). 这将起作用,因为除非组件的大小大于
0
且已附加到本地对等点(在屏幕上),否则绝对不应调用paintComponent
。
This is not a great idea as scaling can take time and you don't want to slow down the paint process if you can avoid it. 这不是一个好主意,因为缩放可能会花费一些时间,并且如果可以避免的话,您也不想拖慢绘制过程。
You could use a ComponentListener
attached to the ImagePanel
and monitor the componentResized
event 您可以使用附加到
ImagePanel
的ComponentListener
并监视componentResized
事件
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
if (i != null) {
generateScaledInstance();
}
}
});
This might be called a number of times in quick succession, so be careful. 这可能会连续多次被调用,所以要小心。
In this case, what I tend to do is use a javax.swing.Timer
set to small delay to coalse the updates down to as few a calls as possible, for example... 在这种情况下,我倾向于使用设置为小延迟的
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();
}
This allows componentResized
to be called a number of times in quick succession, but if the time between exceeds 250 milliseconds, the generateScaledInstance
can be called, as an example... 这允许快速连续调用
componentResized
多次,但是例如,如果两次间隔之间的时间超过250毫秒,则可以调用generateScaledInstance
...
You should also provide a preferredSize
value of a non 0
size by default (remember, the default preferred size of a panel is 0x0
). 还应该提供一种
preferredSize
非的值0
大小默认(记住,一个面板的默认大小优选是0x0
)。 Depending on the layout manager, this could be ignored, but is generally used as a basis for most layout managers... 取决于布局管理器,这可以忽略,但是通常用作大多数布局管理器的基础...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.