2012-09-24 7 views
12

안녕하세요, Java 1.6에서 Swing을 사용하여 GUI 응용 프로그램을 작성하고 있습니다.Java에서 GIF 애니메이션 표시

Swing GUI가로드되는 동안 gif 애니메이션을 표시해야하는 팝업 화면이 있습니다.

내 팝업 화면은 JDialog입니다. 발발했습니다 애니메이션이되는 JDialog에 다음과 같은 방법을 추가 한 JLabel의 표시되어야합니다

ImageIcon myImgIcon = getMyImgIcon(); 
JLabel imageLbl = new JLabel(myImgIcon); 
add(imageLbl, BorderLayout.CENTER); 

는 이제 일 만 표시 GUI 후 애니메이션이로드 된 것입니다. 나는 GUI가로드되는 동안 (내 응용 프로그램에서 무거운 작업) EDT가 너무 바빠서 애니메이션을 실행할 수 없다고 생각합니다.

How do I show a animated GIF image using a thread을 참조하십시오.

이제는 다른 스레드 (EDT 아님)에서 GUI로드를 만드는 것이 잘못되어 문제를 해결하는 방법을 모르겠습니다.

누구나 아이디어가 있습니까?

+5

는 [시작 화면]의 사용을 고려 (http://docs.oracle.com/javase/tutorial/uiswing/misc/splashscreen.html)는 시동을위한 경우 대신 귀하의 응용 프로그램 – Robin

답변

6

일부 무거운 작업의 EDT 스레드를 해제하고 별도의 스레드에서 수행하면됩니다. 이 경우 GIF 애니메이션은 실행중인 다른 프로세스와 함께 작동합니다.

응용 프로그램 인터페이스를 표시 할 때까지는 별도의 스레드 (예 : EDT 내에 있지 않음)에 응용 프로그램 인터페이스를 만들 수도 있습니다. 이후 EDT 내에서 모든 변경 작업을 수행해야합니다. 그렇지 않으면 많은 문제가 발생할 수 있습니다.

나중에 별도의 스레드에서 더 많은 UI 요소를로드 할 수 있습니다. EDT 내부의 표시된 프레임/컨테이너에 추가해야합니다. 이것이 가장 중요한 요소입니다. 모든 인터페이스 업데이트 작업이 EDT에서 만들어진, 다른 모든 다른 스레드 내에서 실행 -

public static void main (String[] args) throws InvocationTargetException, InterruptedException 
{ 
    // Main window 

    final JFrame frame = new JFrame(); 

    final JPanel panel = new JPanel (new FlowLayout (FlowLayout.LEFT, 5, 5)) 
    { 
     public Dimension getPreferredSize() 
     { 
      Dimension ps = super.getPreferredSize(); 
      ps.width = 0; 
      return ps; 
     } 
    }; 
    frame.add (new JScrollPane (panel)); 

    frame.setSize (600, 500); 
    frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); 
    frame.setLocationRelativeTo (null); 

    SwingUtilities.invokeAndWait (new Runnable() 
    { 
     public void run() 
     { 
      frame.setVisible (true); 
     } 
    }); 

    // Load dialog 

    final JDialog load = new JDialog (frame); 

    JPanel panel2 = new JPanel (new BorderLayout()); 
    panel2.setBorder (BorderFactory.createEmptyBorder (15, 15, 15, 15)); 
    load.add (panel2); 

    final JProgressBar progressBar = new JProgressBar (0, 100); 
    panel2.add (progressBar); 

    load.setModal (false); 
    load.pack(); 
    load.setLocationRelativeTo (frame); 

    SwingUtilities.invokeAndWait (new Runnable() 
    { 
     public void run() 
     { 
      load.setVisible (true); 
     } 
    }); 

    // Heavy task (takes approx. 10 seconds + some time on buttons creation) 

    for (int i = 0; i < 100; i++) 
    { 
     Thread.sleep (100); 

     final JButton button = new JButton ("Button" + i); 
     final int finalI = i; 

     // Updating panel and progress in EDT 
     SwingUtilities.invokeLater (new Runnable() 
     { 
      public void run() 
      { 
       panel.add (button); 
       button.revalidate(); 
       progressBar.setValue (finalI); 
      } 
     }); 
    } 
} 

당신이 볼 수 있듯이 :

여기에 "무거운 같은"인터페이스로드의 작은 예입니다.

또한 주 스레드는 EDT 스레드가 아니므로 즉시 무언가를 수행 할 수 있습니다.

경우에 따라 인터페이스의로드 된 부분을 바로 표시 할 필요가 없으므로 "무거운"작업이 끝나면 추가 할 수 있습니다. 그러면 로딩 시간이 절약되고 초기화 코드가 훨씬 간단 해집니다.

간단한 EDT에 대한 설명과 내가 대답했다

...

...그것은 Swing L & F와 많은 Swing 기반 응용 프로그램에서 3 년 근무한 후에 발견 한 무언가였습니다. 나는 많은 스윙 소스를 파고 널리 알려지지 않은 흥미로운 것들을 많이 발견했다.

아시다시피 - 인터페이스 업데이트 (스윙에서의 EDT)에 대한 단일 스레드의 전체 아이디어는 스레드 내에서 하나의 큐에 각각 별도의 구성 요소를 시각 업데이트 (및 이벤트)을 유지하고 그들에게 하나를 수행에 관한 것입니다 . 단일 프레임 안의 모든 구성 요소는 단일 이미지에 그려지기 때문에 페인트 문제를 피하기 위해 주로 필요합니다. 페인팅 순서가 엄격하므로 한 구성 요소가 최종 이미지에서 다른 구성 요소를 덮어 쓰지 않습니다. 페인팅 순서는 다른 컨테이너 안에 일부 구성 요소 또는 컨테이너를 추가하여 만든 구성 요소 트리에 따라 달라집니다 (Swing에서 응용 프로그램 인터페이스를 만들 때 수행하는 기본 작업).

요약하면 ED30 내에서 시각적 인 업데이트 (이를 일으킬 수있는 방법/작업)를 모두 유지해야합니다. 기타 이 EDT 외부에서 수행 될 수 있습니다. 예를 들어 EDT 외부에서 애플리케이션 인터페이스를 준비 할 수 있습니다 (예 : 이미 표시된 컨테이너 내부에서 구성 요소를 추가/제거/이동하지 않는 경우).

매우 드문 경우에도 여전히 내부 문제가있을 수 있습니다.
http://www.velocityreviews.com/forums/t707173-why-does-jdk-1-6-recommend-creating-swing-components-on-the-edt.html

은 짧게 : 오래 전에 여기 그 질문의 좋은 논의가 있었다 6 JDK 버전 일에도 구성 요소의 생성이 문제를 방지하기 위해 EDT 내부에서 수행되어야한다 스윙 문서에 명시된 때문이다. 구성 요소가 생성되는 동안 발생하는 이벤트로 인해 인터페이스가 많이 생성되는 특정 경우에 나타날 수 있습니다.

어쨌든 로더/응용 프로그램이 멈추지 않도록 EDT 외부에 인터페이스를 만들 수 있습니다. 응용 프로그램이 인터페이스 작성 시간에 걸리는 지 여부가 중요하지 않은 다른 경우에는 EDT를 사용해야합니다. 그리고 모든 것이 당신의 사건에 달려 있기 때문에 더 구체적으로 말할 수는 없습니다 ...

+0

흠, 고마워요! 그게 효과가있다. 나는 한 가지 질문을한다. 모든 공식 문서 + 튜토리얼은 온라인에서 발견되었으며 반복적으로 스윙 구성 요소가 EDT에서만 조작되어야한다고 반복적으로 말합니다. 내가 눈에 보이지 않는 한 그것이 중요하지 않다는 것을 누군가가 알았다는 것은 처음입니다. 구성 요소가 보이지 않는 경우 왜 EDT 규칙을 위반할 수 있는지 설명해주십시오. 감사! – whomaniac

+0

@ user1155122 하나의 댓글에 너무 컸기 때문에 설명에 답변을 추가했습니다. –

+0

나는 Mad와 같이 온라인으로 인터넷 검색을하고 있으며 주제에 대한 유용한 정보를 제공 한 유일한 출처입니다. 감사!! – whomaniac

3

어쩌면 곧 시작될 이벤트 나 구성 요소를 방해하지 않고 응용 프로그램 시작시 재생할 애니메이션을 만들려고합니다. 따라서 스플래시 화면을 시도해 볼 수 있습니다. 여기에서 읽어보십시오 : http://docs.oracle.com/javase/tutorial/uiswing/misc/splashscreen.html

위의 링크에서는 프레임 클래스에서 파생 된 SplashScreen이라는 클래스의 사용법을 보여줍니다. 따라서 메커니즘은 다음과 같습니다. 별도의 프레임 (스플래시 화면, 애니메이션이 여기에 표시됨)을 표시하고 잠시 후 기본 응용 프로그램이 시작됩니다.

+0

정말이 스플래시 화면을 사용하고 싶습니다! 나는 정말로한다! 그러나 약간의 문제가 있습니다. main() 메서드가 종료 된 후 원하는 시점에 스플래시 화면을 삭제하고 싶습니다. docs에 따르면 main()이 종료되면 자동으로 종료됩니다! 이 기능을 어떻게 비활성화시킬 수 있습니까? 어떤 아이디어? – whomaniac

+0

@ user1155122 : 스플래시 화면은 main()이있는 경우 삭제됩니다. 모든 main()은 Swing 이벤트 발송 스레드를 시작한 다음 종료합니다. –

1

'ImageIcon'클래스를 사용하면 gif 애니메이션을로드 할 수 있습니다. 'getResource()'로 이미지를로드합니다. 이 일을 위해 일반적으로 우리는 파일 경로를 전달하는 URL 클래스를 사용합니다. 이름이 URL과 같이 원격 시스템에서 필요하지는 않습니다.

URL url = this.getClass().getResource(path); 
Icon myImgIcon = new ImageIcon(url); 
JLabel imageLbl = new JLabel(myImgIcon); 
component.add(imageLbl, BorderLayout.CENTER); 

경로는 클래스 폴더 내부의 gif 경로입니다.

참조 : http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html#getresource

+0

다음을 수정하십시오 : this.getClass(). getResource (path) –