我有一个JPNEL,我想在其中添加我即时生成的JPEG和PNG图像。
到目前为止,我在Swing Tutorials中看到的所有例子,特别是在Swing examples中都使用了`ImageIcon's。
我把这些图像生成为字节数组,它们通常比例子中使用的普通图标大,为640x480。
1.使用ImageIcon类在Jpanel中显示这么大的图像,是否有任何(性能或其他)问题? 2.2.通常*的做法是什么? 3.如何在不使用ImageIcon类的情况下向Jpanel中添加图片?
编辑。对教程和API进行更仔细的检查后发现,你不能直接向Jpanel中添加ImageIcon。相反,他们通过将图像设置为JLabel的图标来达到同样的效果。这感觉不对...。
如果你使用的是JPanels,那么可能是在使用Swing。 试试这个。
BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
add(picLabel);
图像现在是一个摆动组件。 它变得像其他组件一样受布局条件的制约。
以下是我的做法(关于如何加载图像,还有一些信息)。
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class ImagePanel extends JPanel{
private BufferedImage image;
public ImagePanel() {
try {
image = ImageIO.read(new File("image name and path"));
} catch (IOException ex) {
// handle exception...
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this); // see javadoc for more info on the parameters
}
}
Fred Haslam'的方法很好用。 但我在文件路径方面遇到了麻烦,因为我想在我的jar中引用一个图像。 要做到这一点,我使用了
BufferedImage wPic = ImageIO.read(this.getClass().getResource("snow.png"));
JLabel wIcon = new JLabel(new ImageIcon(wPic));
由于我只有有限数量(大约10张)的图片需要用这个方法加载,所以效果很好。 它获取文件时不需要有正确的相对文件路径。
通过使用免费的[SwingX][1]库中的JXImagePanel类,可以完全避免滚动自己的Component子类。
下载][2]
[1]: https://swingx.java.net// [2]: http://java.net/projects/swingx/downloads
你可以对Jpanel进行子类化--这里是我的ImagePanel的摘录,它将图像放在5个位置中的任何一个,顶部/左边,顶部/右边,中间/中间,底部/左边或底部/右边。
protected void paintComponent(Graphics gc) {
super.paintComponent(gc);
Dimension cs=getSize(); // component size
gc=gc.create();
gc.clipRect(insets.left,insets.top,(cs.width-insets.left-insets.right),(cs.height-insets.top-insets.bottom));
if(mmImage!=null) { gc.drawImage(mmImage,(((cs.width-mmSize.width)/2) +mmHrzShift),(((cs.height-mmSize.height)/2) +mmVrtShift),null); }
if(tlImage!=null) { gc.drawImage(tlImage,(insets.left +tlHrzShift),(insets.top +tlVrtShift),null); }
if(trImage!=null) { gc.drawImage(trImage,(cs.width-insets.right-trSize.width+trHrzShift),(insets.top +trVrtShift),null); }
if(blImage!=null) { gc.drawImage(blImage,(insets.left +blHrzShift),(cs.height-insets.bottom-blSize.height+blVrtShift),null); }
if(brImage!=null) { gc.drawImage(brImage,(cs.width-insets.right-brSize.width+brHrzShift),(cs.height-insets.bottom-brSize.height+brVrtShift),null); }
}
我'在我的一个私人项目中正在做一些非常类似的事情。 到目前为止,我'已经生成了高达1024x1024的图像,没有任何问题(除了内存),并且可以非常快速地显示它们,没有任何性能问题。
覆盖JPanel子类的paint方法是矫枉过正的,需要做更多的工作。
我的做法是:{{5415604}}。
Class MapIcon implements Icon {...}
或
Class MapIcon extends ImageIcon {...}
你用来生成图像的代码将在这个类中。 我使用一个BufferedImage来绘制,然后当调用paintIcon()时,使用g.drawImvge(bufferedImage)。 这样就减少了生成图像时的闪烁量,而且你可以用线程来完成。
接下来我扩展了JLabel。
Class MapLabel extends Scrollable, MouseMotionListener {...}
这是因为我想把我的图片放在一个滚动窗格上,即 显示图像的一部分,并让用户根据需要进行滚动。
所以我使用 JScrollPane 来保存 MapLabel,其中只包含 MapIcon。
MapIcon map = new MapIcon ();
MapLabel mapLabel = new MapLabel (map);
JScrollPane scrollPane = new JScrollPane();
scrollPane.getViewport ().add (mapLabel);
但是对于你的方案(每次都显示整个图片即可)。 你需要将MapLabel添加到顶部的JPanel中,并确保它们的大小都是图片的全尺寸(通过覆盖GetPreferredSize())。
我可以看到很多答案,并没有真正解决上级的三个问题。
1)一个关于性能的词。 字节数组很可能是低效的,除非你能使用一个精确的像素字节排序,这与你的显示适配器当前的分辨率和颜色深度相匹配。
要获得最佳的绘图性能,只需将你的图像转换为BufferedImage,BufferedImage的类型与你当前的图形配置相对应。 参见 https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html 中的 createCompatibleImage。
这些图像会在绘制几次后自动缓存在显示卡内存中,无需任何编程工作(这是Swing自Java 6以来的标准),因此,实际绘制将花费微不足道的时间--如果你没有改变图像。
改变图像将伴随着主内存和GPU内存之间的额外内存传输--这很慢。 避免"重绘"。 因此,要避免用任何方式进行getPixel和setPixel。
例如,如果你正在开发一款游戏,与其将所有的游戏角色绘制到BufferedImage中,然后再绘制到JPanel中,不如将所有的角色加载为较小的BufferedImages,然后在JPanel代码中一个一个地绘制到它们的适当位置,这样就会快很多--除了用于缓存的图像的初始传输外,主内存和GPU内存之间没有额外的数据传输。
ImageIcon会在引擎盖下使用一个BufferedImage--但基本上分配一个BufferedImage与_proper_图形模式是关键,没有努力去做好这一点。
2)通常的做法是在JPanel的重载paintComponent方法中绘制BufferedImage。 虽然Java支持大量额外的好东西,比如控制GPU内存中缓存的VolatileImages的缓冲链,但自Java 6以来,没有必要使用这些东西,它在不暴露GPU加速的所有这些细节的情况下做得相当好。
注意,GPU加速可能对某些操作不起作用,比如拉伸半透明图像。
3)不要添加。 按上面提到的画法画就可以了。
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
"添加"。 如果图像是布局的一部分,那就有意义了。 如果你需要将其作为填充JPanel的背景或前景图像,只需在paintComponent中绘制即可。 如果你喜欢酝酿一个通用的Swing组件,它可以显示你的图像,那么它是同样的故事(你可以使用一个JComponent,并覆盖它的paintComponent方法)--然后将_这个_添加到你的GUI组件布局中。
4)如何将数组转换为Bufferedimage(缓冲图像)
将你的字节数组转换为PNG,然后加载它是相当耗费资源的。 一个更好的方法是将现有的字节数组转换为BufferedImage。
为此。 不要使用for循环_和复制像素。 那是非常非常慢的。 取而代之的是: * 学习首选的字节结构。