JPanel에 이미지를 추가하는 방법?


341

나는이 JPanel의 나는 즉시 생성 할 것을 JPEG 및 PNG 이미지를 추가하고 싶은에 있습니다.

지금까지 Swing Tutorials 에서 본 모든 예제 , 특히 Swing 예제 에서는 ImageIcons를 사용 합니다.

이 이미지를 바이트 배열로 생성하고 있으며 일반적으로 640x480에서 예제에서 사용하는 공통 아이콘보다 큽니다.

  1. ImageIcon 클래스를 사용하여 JPanel에 해당 크기의 이미지를 표시 할 때 (성능 또는 기타) 문제가 있습니까?
  2. 일반적인 방법은 무엇입니까 ?
  3. ImageIcon 클래스를 사용하지 않고 JPanel에 이미지를 추가하는 방법은 무엇입니까?

편집 : 자습서 및 API를 자세히 살펴보면 ImagePacon을 JPanel에 직접 추가 할 수 없음을 알 수 있습니다. 대신 이미지를 JLabel의 아이콘으로 설정하여 동일한 효과를 얻습니다. 이건 그냥 기분이 좋지 않아 ...


1
바이트 배열을 생성하는 방법에 따라 a를 사용 MemoryImageSource하여 JPEG 또는 PNG 형식으로 변환 한 다음 ImageIO대부분의 답변에서 제시 하는 대로 읽는 것이 더 효율적일 수 있습니다 . 을 사용하여 이미지 데이터로 구성 Image된 것을 얻을 수 있으며 답변 중 하나에서 제안 된대로 표시 할 수 있습니다. MemoryImageSourcecreateImage
Alden

답변:


252

내가하는 방법은 다음과 같습니다 (이미지를로드하는 방법에 대한 정보가 조금 더 있습니다).

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            
    }

}

17
-1의 paintComponent의 잘못된 구현 (의 왜 당신이 그 다시 그릴에 문제가있는 것을 아마 @Dogmatixed) -이 있어야 이되는 불투명 (기본값)보고하는 경우는 전체 영역을 커버하는 garantee, 쉬운 super.paintComponent를 호출하여 달성
kleopatra

5
@kleopatra, 고마워, 나는 그것을 몰랐다 ... javadoc에 따르면 : "따라서, 당신은 super의 구현을 호출하지 않으면 opaque 속성을 존중해야합니다. 즉,이 구성 요소가 불투명하면 완전히 채워야합니다 불투명 한 색상의 배경을 사용합니다. 불투명 한 속성을 사용하지 않으면 시각적 인 결함이있을 수 있습니다. " 지금 답변을 업데이트하겠습니다.
Brendan Cashman

8
항상 존중하십시오 Principle of Encapsulation,의 액세스 지정자 슈퍼 클래스의 오버라이드 (override) 동안 방법을 paintComponent(...)방법이 protected아니라 public:-)
좋은 암소

1
이것은 좋지 않습니다. 패널 크기를 이미지 크기로 조정하는 것과 관련이 없습니다. 이 문제를 해결하려면 나중에 더 많은 코드를 추가해야합니다. JLabel 답변을 사용하는 것이 훨씬 간단합니다.
Keilly

2
@Jonathan :의 소스에 대해서는 정말 죄송합니다 Principle of Encapsulation. 프로그래밍하는 동안 나머지 코드에서 숨겨져 야하는 것은 코드의 모든 것에 표시되는 대신 그 방식으로 유지해야한다는 것을 기억하십시오. 매일 배우는 것처럼 경험과 함께 제공되는 것 같습니다. 어떤 책이든 캡슐화가 무엇인지에 대한 기본 아이디어를 줄 수 있지만 개념을 얼마나 준수 할 것인지 결정하는 것은 코드를 구현하는 방법입니다.
5

520

JPanel을 사용하는 경우 아마도 Swing으로 작업하고있을 것입니다. 이 시도:

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

이미지는 이제 스윙 구성 요소입니다. 다른 구성 요소와 마찬가지로 레이아웃 조건이 적용됩니다.


16
JLabel의 크기에 따라 이미지 크기를 조정하는 방법은 무엇입니까?
coding_idiot

1
좋은 코드! Swing에 대한 경험이 많지 않지만 작동하지 않습니다. 아무도 jdk 1.6.0_16에서 시도 했습니까?
ATorras

3
@ATorras 나는 당신이 이것을 잠시 동안 물었다는 것을 알고 있지만 다른 초보자가 내 문제를 가지고 있다면, picLabel.setBounds ();를 기억하십시오.
kyle

사진을 다시로드 할 때마다 새 JLabel 객체를 만들어야합니까?
0x6B6F77616C74

2
@coding_idiot new JLabel (새 ImageIcon (backgroundImage.getScaledInstance (너비, 높이, Image.SCALE_FAST)));
Davide

37

프레드 하 슬람의 방식은 잘 작동합니다. 항아리 내에서 이미지를 참조하고 싶기 때문에 파일 경로에 문제가있었습니다. 이를 위해 다음을 사용했습니다.

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

이 방법을 사용하여로드 해야하는 유한 번호 (약 10 개)의 이미지 만 가지고 있기 때문에 잘 작동합니다. 올바른 상대 파일 경로가 없어도 파일을 가져옵니다.


1
BufferedImage previewImage = ImageIO.read(new URL(imageURL));서버에서 이미지를 얻기 위해 첫 번째 줄로 대체했습니다 .
intcreator

jar의 이미지를 참조하려면이 stackoverflow.com/a/44844922/3211801
Nandha

33

나는 아무것도 서브 클래스 할 필요가 없다고 생각합니다. Jlabel을 사용하십시오. 이미지를 Jlabel로 설정할 수 있습니다. 따라서 Jlabel의 크기를 조정 한 다음 이미지로 채우십시오. 괜찮아. 이것이 내가하는 방식입니다.


20

무료 SwingX 라이브러리 에서 JXImagePanel 클래스를 사용하여 자체 컴포넌트 서브 클래스를 완전히 롤링하지 않아도 됩니다.

다운로드


11
JLabel imgLabel = new JLabel(new ImageIcon("path_to_image.png"));

8

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); }
    }

8
  1. 큰 이미지에서 발생할 수있는 일반적인 문제 이외의 문제는 없어야합니다.
  2. 단일 패널에 여러 이미지를 추가하는 것에 대해 이야기하는 경우 ImageIcons를 사용 합니다. 단일 이미지의 경우 이미지를 그리는 사용자 정의 하위 클래스를 JPanel만들고 해당 paintComponent메서드를 재정의하는 방법을 생각 합니다.
  3. (2 참조)

6

JPanel서브 클래스는 거의 항상 잘못된 클래스입니다. 왜 서브 클래스가되지 JComponent않습니까?

ImageIcon생성자가 이미지 읽기를 차단한다는 점에서 약간의 문제가 있습니다. 응용 프로그램 jar에서로드 할 때 실제로 문제는 아니지만 네트워크 연결을 통해 잠재적으로 읽을 수 있습니다. AWT 시대의 사용 예는 많이있다 MediaTracker, ImageObserver친구 심지어 JDK 데모에.


6

내가 작업중 인 개인 프로젝트에서 매우 비슷한 일을하고 있습니다. 지금까지 문제없이 메모리를 제외하고 최대 1024x1024의 이미지를 생성했으며 성능 문제없이 매우 빠르게 이미지를 표시 할 수 있습니다.

JPanel 서브 클래스의 paint 메소드를 대체하는 것은 과도하며 필요한 것보다 많은 작업이 필요합니다.

내가하는 방법은 다음과 같습니다.

Class MapIcon implements Icon {...}

또는

Class MapIcon extends ImageIcon {...}

이미지를 생성하는 데 사용하는 코드는이 클래스에 있습니다. BufferedImage를 사용하여 paintIcon ()이 호출되면 g.drawImvge (bufferedImage)를 사용합니다. 이렇게하면 이미지를 생성하는 동안 수행되는 깜박이는 양이 줄어들고 이미지를 스레드 할 수 있습니다.

다음으로 JLabel을 확장합니다.

Class MapLabel extends Scrollable, MouseMotionListener {...}

이미지를 스크롤 창에 놓고 이미지의 일부를 표시하고 필요에 따라 사용자가 스크롤하도록하기 때문입니다.

그런 다음 JScrollPane을 사용하여 MapIcon 만 포함하는 MapLabel을 보유합니다.

MapIcon map = new MapIcon (); 
MapLabel mapLabel = new MapLabel (map);
JScrollPane scrollPane = new JScrollPane();

scrollPane.getViewport ().add (mapLabel);

그러나 시나리오의 경우 (매번 전체 이미지를 표시하십시오). MapLabel을 맨 위 JPanel에 추가하고 GetPreferredSize ()를 재정 의하여 이미지의 전체 크기로 모두 크기를 조정해야합니다.


5

프로젝트 디렉토리에 소스 폴더를 작성하십시오.이 경우에는 이미지라고합니다.

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

5

자신 Component과 SwingX 라이브러리 및 ImageIO클래스 사용을 피할 수 있습니다 .

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

4

이 답변은 @shawalli의 답변을 보완합니다 ...

내 항아리 내에서 이미지를 참조하고 싶었지만 BufferedImage 대신에 이것을 간단하게 수행했습니다.

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

1

OP의 세 가지 질문을 다루지 않고 많은 답변을 볼 수 있습니다.

1) 성능에 관한 단어 : 바이트 배열은 디스플레이 어댑터의 현재 해상도 및 색상 깊이와 일치하는 정확한 픽셀 바이트 순서를 사용할 수 없다면 비효율적입니다.

최상의 그리기 성능을 얻으려면 이미지를 현재 그래픽 구성에 해당하는 유형으로 생성 된 BufferedImage로 변환하십시오. https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html 에서 createCompatibleImage를 참조하십시오.

이러한 이미지는 프로그래밍 노력없이 몇 번 그린 후 디스플레이 카드 메모리에 자동으로 캐시되므로 (Java 6 이후 Swing의 표준 임) 이미지를 변경하지 않은 경우 실제 드로잉에는 시간이 거의 걸리지 않습니다. .

이미지를 변경하면 주 메모리와 GPU 메모리 사이에 추가 메모리 전송이 제공되며 속도가 느립니다. 이미지를 BufferedImage에 "다시 그리기"하지 말고 getPixel 및 setPixel을 수행하지 마십시오.

예를 들어, 게임을 개발하는 경우 모든 게임 액터를 BufferedImage에 그리고 JPanel에 그리는 대신 모든 액터를 더 작은 BufferedImage로로드하고 JPanel 코드에서 하나씩 하나씩 그리는 것이 훨씬 빠릅니다. 올바른 위치-이 방법으로 캐싱을위한 이미지의 초기 전송을 제외하고 메인 메모리와 GPU 메모리간에 추가 데이터 전송이 없습니다.

ImageIcon은 후드 아래에서 BufferedImage를 사용하지만 기본적으로 적절한 그래픽 모드 를 사용하여 BufferedImage를 할당하는 것이 중요하며이를 올바르게 수행하기위한 노력이 없습니다.

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) 배열을 버퍼 이미지로 변환하는 방법

바이트 배열을 PNG로 변환 한 다음로드하는 데 많은 리소스가 필요합니다. 더 좋은 방법은 기존 바이트 배열을 BufferedImage로 변환하는 것입니다.

이를 위해 : 루프에 사용하지 않고 픽셀을 복사하십시오. 매우 느립니다. 대신 :

  • BufferedImage의 선호 바이트 구조를 배우십시오 (현재 RGB 또는 RGBA (픽셀 당 4 바이트)라고 가정하는 것이 안전합니다)
  • 사용중인 스캔 라인 및 스캔 크기를 익히십시오 (예 : 너비가 142 픽셀 일 수 있지만 GPU 하드웨어에 의해 처리되지 않고 사용되지 않은 픽셀을 마스크하는 것이 더 빠르기 때문에 실제로는 256 픽셀 너비의 바이트 배열로 저장 됨) )
  • 그런 다음 이러한 원칙에 따라 배열을 구축하면 BufferedImage의 setRGB 배열 메소드가 배열을 BufferedImage에 복사 할 수 있습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.