如果这很难理解,请原谅我,但我有一个特殊的问题,我需要帮助解决。我已经做了大量的研究,我尝试了很多解决方案,但没有一个能够正常工作。
我的问题是我有一个ImagePanel
类正在扩展JPanel
(下面的代码),这个类需要使用宽度和高度来缩放图像(我正在创建一个用户可以创建的程序)自定义教程,包括图像)。当我实例化这个时,我得到一个错误,说宽度和高度必须非零。我理解这是因为布局管理器尚未通过ImagePanel
首选大小,但我不知道如何将该大小传递给面板。 ImagePanel
位于JPanel
内JSplitPane
内JScrollPane
内JPanel
内JTabbedPane
内JSplitPane
内JFrame
内的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的代码如下:
ImagePanel
如何才能获得JFrame
的正确尺寸。我希望图片的大小会随setPreferedSize();
的大小而变化,这就是为什么我不能使用{{1}}。
答案 0 :(得分:4)
我希望图片能够根据JFrame的大小来改变大小
您可以使用Darryl' s Stretch Icon,而不是在自己的组件中进行自定义绘画。图标将根据可用空间自动调整大小。
这就是为什么我不使用' setPreferedSize();'。
如果您使用自定义绘画,则不应使用setPreferredSize()。您应该重写getPreferredSize()
方法以返回图像的大小。请记住,首选大小只是对布局管理器的建议。布局管理器可以使用或忽略大小。
如果要在paintComponent()方法中自动缩放图像,则代码应为:
Dimension d = getSize();
g.drawImage(paint, 0, 0, d.width, d.height, this);
因此,您的代码中的真正挑战(无论您选择哪种解决方案)都是为了确保您使用的布局管理器将为您的组件提供所有可用空间,以便可以自动缩放图像。
答案 1 :(得分:3)
至少有两种方法可以实现,第一种方法是允许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);
}
}
这将起作用,因为永远不应该调用paintComponent
,除非组件的大小大于0
并且附加到本地对等方(在屏幕上)。
这不是一个好主意,因为缩放可能需要一些时间,如果你能避免它,你不想放慢绘画过程。
您可以使用附加到ComponentListener
的{{1}}并监控ImagePanel
事件
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();
}
,但如果时间间隔超过250毫秒,则可以调用componentResized
作为示例...
默认情况下,您还应提供非generateScaledInstance
大小的preferredSize
值(请记住,面板的默认首选大小为0
)。根据布局管理器的不同,这可以忽略,但通常用作大多数布局管理器的基础......