JPanel的宽度和高度为0(具体情况) [英] 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.
我的问题是我有一个 ImagePanel
类正在扩展 JPanel
(下面的代码),这个类需要使用宽度和高度来缩放图像(我正在创建一个程序,用户可以创建自定义教程,包括图像)。当我实例化这个时,我得到一个错误,说宽度和高度必须非零。我知道这是因为布局管理器尚未传递 ImagePanel
首选大小,但我不知道如何将该大小传递给面板。 ImagePanel
位于 JPanel
内,该内容位于 JSplitPane
内 JScrollPane
里面的 JPanel
里面的 JTabbedPane
在 JFrame
内的 JSplitPane
内。递减容器订单的图形表示如下:
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). 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. 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
. A graphical representation of this in decreasing container order is as follows:
- JFrame(GridLayout)
- JSplitPane(默认SplitPane布局)
- JTabbedPane(Deault JTabbedPane布局)
- JPanel(GridLayout)
- JScrollPane (默认ScrollPane布局)
- JSplitPane(默认SplitPane布局)
- JPanel(GridLayout);
- ImagePanel
- JFrame (GridLayout)
- JSplitPane (Default SplitPane Layout)
- JTabbedPane (Deault JTabbedPane Layout)
- JPanel (GridLayout)
- JScrollPane (Default ScrollPane Layout)
- JSplitPane (Default SplitPane Layout)
- JPanel (GridLayout);
- ImagePanel
ImagePanel的代码如下:
The code for the ImagePanel is as follows:
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();
。
How can I get the proper size to the ImagePanel
. I would like the image to change size with the size of the JFrame
, which is why I don't just use setPreferedSize();
.
推荐答案
至少有两种方法可以实现,第一种方法是允许 paintComponent
检查 paint
的状态,并在 null $时适当地重新缩放图像c $ c>
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
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (i != null && paint == null){
generateScaledInstance();
}
if (paint != null) {
g.drawImage(paint, 0, 0, this);
}
}
这将起作用,因为 paintComponent除非组件的大小大于
,并将其附加到本机对等方(在屏幕上)。 0
,否则永远不应该调用
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).
这不是一个好主意,因为缩放可能需要一些时间,如果你能避免它,你不想放慢绘画过程。
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.
您可以使用附加到 ImagePanel
的 ComponentListener
并监控 componentResized
event
You could use a ComponentListener
attached to the ImagePanel
and monitor the componentResized
event
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.
在这种情况下,我倾向于使用 javax.swing.Timer
设置为小延迟以将更新下载到尽可能少的电话,例如......
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...
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
作为示例......
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...
默认情况下,您还应提供非 0
大小的 preferredSize
值(请记住,面板的默认首选大小是 0x0
)。根据布局管理器的不同,这可以忽略,但通常用作大多数布局管理器的基础......
You should also provide a preferredSize
value of a non 0
size by default (remember, the default preferred size of a panel is 0x0
). Depending on the layout manager, this could be ignored, but is generally used as a basis for most layout managers...
这篇关于JPanel的宽度和高度为0(具体情况)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!