如何在Jpanel上添加图片?

我有一个JPNEL,我想在其中添加我即时生成的JPEG和PNG图像。

到目前为止,我在Swing Tutorials中看到的所有例子,特别是在Swing examples中都使用了`ImageIcon's。

我把这些图像生成为字节数组,它们通常比例子中使用的普通图标大,为640x480。

1.使用ImageIcon类在Jpanel中显示这么大的图像,是否有任何(性能或其他)问题? 2.2.通常*的做法是什么? 3.如何在不使用ImageIcon类的情况下向Jpanel中添加图片?

编辑。对教程和API进行更仔细的检查后发现,你不能直接向Jpanel中添加ImageIcon。相反,他们通过将图像设置为JLabel的图标来达到同样的效果。这感觉不对...。

对该问题的评论 (2)

如果你使用的是JPanels,那么可能是在使用Swing。 试试这个。

BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
add(picLabel);

图像现在是一个摆动组件。 它变得像其他组件一样受布局条件的制约。

评论(6)
解决办法

以下是我的做法(关于如何加载图像,还有一些信息)。

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            
    }

}
评论(7)

Fred Haslam'的方法很好用。 但我在文件路径方面遇到了麻烦,因为我想在我的jar中引用一个图像。 要做到这一点,我使用了

BufferedImage wPic = ImageIO.read(this.getClass().getResource("snow.png"));
JLabel wIcon = new JLabel(new ImageIcon(wPic));

由于我只有有限数量(大约10张)的图片需要用这个方法加载,所以效果很好。 它获取文件时不需要有正确的相对文件路径。

评论(2)

我认为没有必要对任何东西进行子类。 只要使用一个Jlabel就可以了。 你可以在Jlabel中设置一张图片。 所以,调整Jlabel的大小,然后用图片填充。 就可以了。 我是这样做的。

评论(0)

通过使用免费的[SwingX][1]库中的JXImagePanel类,可以完全避免滚动自己的Component子类。

下载][2]

[1]: https://swingx.java.net// [2]: http://java.net/projects/swingx/downloads

评论(0)
JLabel imgLabel = new JLabel(new ImageIcon("path_to_image.png"));
评论(0)

1.不应该有任何问题(除了你在处理非常大的图像时可能遇到的任何一般问题)。 2.2. 如果你想在一个面板上添加多张图片,我会使用ImageIcon's。对于单个图像,我会考虑制作一个自定义的JPanel'子类,并重写其`paintComponent'方法来绘制图像。 3.(见2)

评论(0)

你可以对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); }
    }
评论(0)

我'在我的一个私人项目中正在做一些非常类似的事情。 到目前为止,我'已经生成了高达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())。

评论(0)

JPanel几乎总是错误的子类。 为什么不把JComponent子类化呢?

ImageIcon有一个小问题,因为构造函数会阻止读取图像。 当从应用程序jar中加载时,这并不是一个真正的问题,但如果你有可能通过网络连接进行读取,则可能是一个问题。 有很多AWT时代使用MediaTrackerImageObserver和朋友的例子,甚至在JDK演示中。

评论(0)

在你的项目目录下创建一个源文件夹,在本例中我把它叫做Images。

JFrame snakeFrame = new JFrame();
snakeFrame.setBounds(100, 200, 800, 800);
snakeFrame.setVisible(true);
snakeFrame.add(new JLabel(new ImageIcon("Images/Snake.png")));
snakeFrame.pack();
评论(0)

这个答案是对@shawalli'答案的补充......

我也想在我的 jar 中引用一张图片,但我没有使用 BufferedImage,而是简单地这样做。

 JPanel jPanel = new JPanel();      
 jPanel.add(new JLabel(new ImageIcon(getClass().getClassLoader().getResource("resource/images/polygon.jpg"))));
评论(0)

可以避免使用自己的 "组件 "和SwingX库以及 "ImageIO "类。

File f = new File("hello.jpg");
JLabel imgLabel = new JLabel(new ImageIcon(file.getName()));
评论(0)

我可以看到很多答案,并没有真正解决上级的三个问题。

1)一个关于性能的词。 字节数组很可能是低效的,除非你能使用一个精确的像素字节排序,这与你的显示适配器当前的分辨率和颜色深度相匹配。

要获得最佳的绘图性能,只需将你的图像转换为BufferedImage,BufferedImage的类型与你当前的图形配置相对应。 参见 https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html 中的 createCompatibleImage。

这些图像会在绘制几次后自动缓存在显示卡内存中,无需任何编程工作(这是Swing自Java 6以来的标准),因此,实际绘制将花费微不足道的时间--如果你没有改变图像。

改变图像将伴随着主内存和GPU内存之间的额外内存传输--这很慢。 避免"重绘&quot。 因此,要避免用任何方式进行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); 
}

"添加&quot。 如果图像是布局的一部分,那就有意义了。 如果你需要将其作为填充JPanel的背景或前景图像,只需在paintComponent中绘制即可。 如果你喜欢酝酿一个通用的Swing组件,它可以显示你的图像,那么它是同样的故事(你可以使用一个JComponent,并覆盖它的paintComponent方法)--然后将_这个_添加到你的GUI组件布局中。

4)如何将数组转换为Bufferedimage(缓冲图像)

将你的字节数组转换为PNG,然后加载它是相当耗费资源的。 一个更好的方法是将现有的字节数组转换为BufferedImage。

为此。 不要使用for循环_和复制像素。 那是非常非常慢的。 取而代之的是: * 学习首选的字节结构。

  • 学习BufferedImage的首选字节结构(现在可以放心地假设为RGB或RGBA,每个像素4个字节)。
  • 学习使用中的扫描线和扫描大小(例如 你可能有一个142像素宽的图像--但在现实生活中,它将被存储为256像素宽的字节数组,因为GPU硬件处理它和掩盖未使用的像素会更快。)
  • 那么一旦你按照这些原则建立了一个数组,BufferedImage的setRGB数组方法就可以把你的数组复制到BufferedImage中。
评论(0)