JPanel的宽度和高度为0(具体情况) [英] Width and height of a JPanel are 0 (Specific Situation)

查看:158
本文介绍了JPanel的宽度和高度为0(具体情况)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果这很难理解,请原谅我,但我有一个特殊的问题,我需要帮助解决。我已经做了大量的研究,我尝试了很多解决方案,但没有一个是有效的。

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:


  1. JFrame(GridLayout)

  2. JSplitPane(默认SplitPane布局)

  3. JTabbedPane(Deault JTabbedPane布局)

  4. JPanel(GridLayout)

  5. JScrollPane (默认ScrollPane布局)

  6. JSplitPane(默认SplitPane布局)

  7. JPanel(GridLayout);

  8. ImagePanel

  1. JFrame (GridLayout)
  2. JSplitPane (Default SplitPane Layout)
  3. JTabbedPane (Deault JTabbedPane Layout)
  4. JPanel (GridLayout)
  5. JScrollPane (Default ScrollPane Layout)
  6. JSplitPane (Default SplitPane Layout)
  7. JPanel (GridLayout);
  8. 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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆