Как добавить изображение в JPanel? - PullRequest
328 голосов
/ 18 ноября 2008

У меня есть JPanel , к которому я хотел бы добавить изображения JPEG и PNG, которые я генерирую на лету.

Все примеры, которые я видел до сих пор в Swing Tutorials , особенно в Swing, use ImageIcon s.

Я генерирую эти изображения в виде байтовых массивов, и они обычно больше, чем общий значок, который они используют в примерах, в 640x480.

  1. Есть ли какая-либо (производительность или другая) проблема в использовании класса ImageIcon для отображения изображения такого размера в JPanel?
  2. Каков обычный способ сделать это?
  3. Как добавить изображение в JPanel без использования класса ImageIcon?

Редактировать : Более тщательное изучение учебников и API показывает, что вы не можете добавить ImageIcon непосредственно в JPanel. Вместо этого они достигают того же эффекта, устанавливая изображение в виде значка JLabel. Это просто нехорошо ...

Ответы [ 14 ]

5 голосов
/ 18 апреля 2016

Создайте исходную папку в каталоге вашего проекта, в данном случае я назвал ее 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();
4 голосов
/ 30 сентября 2015

Этот ответ является дополнением к ответу @ shawalli ...

Я тоже хотел сослаться на изображение внутри моей банки, но вместо BufferedImage я просто сделал это:

 JPanel jPanel = new JPanel();      
 jPanel.add(new JLabel(new ImageIcon(getClass().getClassLoader().getResource("resource/images/polygon.jpg"))));
3 голосов
/ 23 февраля 2018

Вы можете избежать использования собственной Component s и библиотеки SwingX и ImageIO class:

File f = new File("hello.jpg");
JLabel imgLabel = new JLabel(new ImageIcon(file.getName()));
0 голосов
/ 10 марта 2018

Я вижу много ответов, на самом деле не обращаясь к трем вопросам ОП.

1) Слово о производительности: байтовые массивы, вероятно, неэффективны, если вы не можете использовать точный порядок следования байтов в пикселях, соответствующий вашим адаптерам дисплея, текущему разрешению и глубине цвета.

Чтобы добиться максимальной производительности при рисовании, просто конвертируйте ваше изображение в BufferedImage, которое генерируется с типом, соответствующим вашей текущей графической конфигурации. См. CreateCompatibleImage на https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html

Эти изображения будут автоматически кэшироваться в памяти видеокарты после рисования несколько раз без каких-либо усилий по программированию (это стандартно в Swing начиная с Java 6), и, следовательно, фактическое рисование займет незначительное количество времени - , если Вы не изменили изображение.

Изменение изображения сопровождается дополнительной передачей памяти между основной памятью и памятью графического процессора, что является медленным. Избегайте «перерисовки» изображения в BufferedImage, поэтому избегайте использования getPixel и setPixel во всех отношениях.

Например, если вы разрабатываете игру, вместо того, чтобы рисовать всех игровых акторов в BufferedImage, а затем в JPanel, намного быстрее загружать всех акторов как меньшие BufferedImages и рисовать их по одному в вашем Код JPanel в правильном положении - таким образом, нет никакой дополнительной передачи данных между основной памятью и памятью GPU, кроме начальной передачи изображений для кэширования.

ImageIcon будет использовать BufferedImage под капотом - но в основном выделение BufferedImage с правильным графическим режимом является ключевым, и нет никаких усилий, чтобы сделать это правильно.

2) Обычный способ сделать это - нарисовать BufferedImage в переопределенном методе paintComponent в JPanel. Хотя Java поддерживает большое количество дополнительных полезных функций, таких как цепочки буферов, управляющие VolatileImages, кэшируемыми в памяти графического процессора, нет необходимости использовать ни один из них, поскольку Java 6 работает достаточно хорошо, не раскрывая всех этих деталей ускорения графического процессора.

Обратите внимание, что ускорение графического процессора может не работать для определенных операций, таких как растяжение полупрозрачных изображений.

3) Не добавлять. Просто нарисуйте, как указано выше:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawImage(image, 0, 0, this); 
}

«Добавление» имеет смысл, если изображение является частью макета. Если вам нужно это как фоновое или переднее изображение, заполняющее JPanel, просто нарисуйте paintComponent. Если вы предпочитаете создавать универсальный компонент Swing, который может отображать ваше изображение, то это та же история (вы можете использовать JComponent и переопределить его метод paintComponent), а затем добавить this в свой макет компонентов GUI.

4) Как преобразовать массив в Bufferedimage

Преобразование ваших байтовых массивов в PNG с последующей их загрузкой довольно ресурсоемко. Лучший способ - преобразовать существующий байтовый массив в BufferedImage.

Для этого: не использовать для циклов и копировать пиксели. Это очень, очень медленно. Вместо этого:

  • узнать предпочитаемую структуру байтов BufferedImage (в настоящее время можно предположить RGB или RGBA, что составляет 4 байта на пиксель)
  • изучите отсканированную линию и размер сканирования при использовании (например, у вас может быть изображение шириной 142 пикселя - но в реальной жизни оно будет храниться в виде байтового массива шириной 256 пикселей, поскольку это быстрее обрабатывать и маскировать неиспользуемые пиксели с помощью аппаратное обеспечение графического процессора)
  • затем, если у вас есть сборка массива в соответствии с этими принципами, метод массива setRGB объекта BufferedImage может скопировать ваш массив в BufferedImage.
...