2012-09-24 48 views
12

Xin chào Tôi đang viết một ứng dụng GUI trên Java 1.6 với Swing.Hiển thị hình động Gif trong java

Tôi có một màn hình bật lên sẽ hiển thị hình động gif trong khi gui Swing của tôi đang tải và cũng sau một chút.

Màn hình bật lên của tôi là một JDialog. Tthe hoạt hình sẽ được hiển thị trên một JLabel đã được bổ sung vào JDialog theo cách sau:

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

Bây giờ điều đó là phim hoạt hình chỉ hiển thị sau khi gui đã được tải. Tôi tin rằng trong khi GUI đang tải (mà là một hoạt động nặng trong ứng dụng của tôi) EDT là rất bận rộn nó không thể chạy các hình ảnh động.

Xem How do I show a animated GIF image using a thread.

Bây giờ vấn đề là tôi có thể làm cho GUI tải trên một luồng khác (không phải là EDT) vì vậy tôi không biết cách giải quyết vấn đề.

Có ai có ý tưởng không?

+5

Xem xét sử dụng một [màn hình splash] (http://docs.oracle.com/javase/tutorial/uiswing/misc/splashscreen.html) thay vì nếu nó là dành cho khởi nghiệp ứng dụng của bạn – Robin

Trả lời

6

Bạn chỉ cần miễn phí chuỗi chủ đề của một số tác vụ nặng và thực hiện chúng trong một chuỗi riêng biệt. Trong trường hợp đó, hoạt ảnh gif sẽ hoạt động cùng với các quá trình khác đang chạy.

Bạn cũng có thể tạo giao diện ứng dụng của mình trong một chuỗi riêng biệt (có, không phải bên trong EDT) nhưng chỉ cho đến khi bạn hiển thị nó. Sau đó bạn phải thực hiện tất cả các thay đổi bên trong EDT, nếu không bạn có thể gặp phải rất nhiều vấn đề.

Bạn cũng có thể tải thêm phần tử giao diện người dùng trong một chuỗi riêng biệt sau này, chỉ cần đảm bảo rằng bạn thêm chúng vào khung/vùng hiển thị bên trong EDT - đó là điều quan trọng nhất.

Dưới đây là một ví dụ nhỏ của "nặng giống như" giao diện tải:

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

Như bạn có thể nhìn thấy - tất cả các hoạt động cập nhật giao diện được thực hiện trong EDT, mọi thứ khác chạy bên trong các chủ đề khác.

Cũng lưu ý rằng chủ đề chính không phải là chuỗi EDT, vì vậy chúng tôi có thể làm điều gì đó nặng ở đó ngay lập tức.

Trong một số trường hợp, nó không cần thiết để hiển thị các phần được tải của giao diện ngay lập tức, vì vậy bạn có thể thêm chúng hoàn toàn vào cuối hoạt động "nặng". Điều đó sẽ tiết kiệm thời gian tải và sẽ làm cho mã khởi tạo đơn giản hơn nhiều.

giải thích tóm tắt về EDT và những gì tôi đã nói trong câu trả lời ...

...nó là cái gì tôi tìm thấy sau khi làm việc ba năm dưới Swing L & F và rất nhiều ứng dụng dựa trên Swing. Tôi đào rất nhiều nguồn Swing và tìm thấy rất nhiều điều thú vị mà không được biết đến rộng rãi.

Như bạn đã biết - toàn bộ ý tưởng về chuỗi đơn cho bản cập nhật giao diện (EDT của nó trong Swing) là giữ mỗi thành phần riêng biệt trực quan cập nhật (và sự kiện của nó) trong hàng đợi và thực hiện từng cái một . Điều đó là cần thiết chủ yếu để tránh các vấn đề về sơn vì mọi thành phần bên trong một khung hình được vẽ lên ảnh đơn được lưu giữ trong bộ nhớ. Thứ tự sơn là nghiêm ngặt ở đó nên một thành phần sẽ không ghi đè lên hình ảnh cuối cùng khác. Thứ tự sơn phụ thuộc vào cây thành phần được tạo ra bằng cách thêm một số thành phần hoặc thùng chứa bên trong một vùng chứa khác (đó là điều cơ bản bạn thực hiện khi tạo bất kỳ giao diện ứng dụng nào trên Swing).

Để tóm tắt - bạn phải giữ tất cả trực quan cập nhật (phương pháp/hoạt động có thể gây ra chúng) bên trong EDT. Bất cứ điều gì khác có thể được thực hiện bên ngoài EDT - ví dụ bạn có thể chuẩn bị giao diện ứng dụng bên ngoài EDT (một lần nữa, trừ khi bạn thêm/xóa/di chuyển thành phần bên trong một vùng chứa đã hiển thị).

Vẫn còn có thể có một số vấn đề nội bộ với điều đó trong một số trường hợp rất rất rất hiếm. Đã có một cuộc thảo luận tốt của câu hỏi đó một thời gian dài trước đây:
http://www.velocityreviews.com/forums/t707173-why-does-jdk-1-6-recommend-creating-swing-components-on-the-edt.html

Để có ngắn: từ 6 phiên bản JDK Sun ghi trong tài liệu mà ngay cả Swing thành phần tạo nên được thực hiện bên EDT để tránh thể vấn đề. Chúng có thể xuất hiện trong một số trường hợp cụ thể với việc tạo giao diện nặng do các sự kiện xảy ra trong khi các thành phần được tạo ra.

Dù sao, tôi muốn nói rằng trong một số trường hợp, bạn có thể tạo giao diện bên ngoài EDT để tránh trình tải/ứng dụng bị kẹt. Trong các trường hợp khác, khi nó không quan trọng nếu ứng dụng bị mắc kẹt cho thời gian tạo giao diện - bạn nên sử dụng EDT. Và tôi không thể nói bất cứ điều gì cụ thể hơn vì mọi thứ phụ thuộc vào trường hợp của bạn ...

+0

Hmm, cảm ơn! Rằng sẽ làm việc. Tôi có một câu hỏi cho bạn mặc dù. Mọi tài liệu hướng dẫn chính thức + hướng dẫn tìm thấy trực tuyến một cách rõ ràng và liên tục nói rằng các thành phần swing chỉ nên được thao tác trên EDT. Đây là lần đầu tiên tôi thấy ai đó nói rằng chừng nào họ còn vô hình thì cũng không thành vấn đề. Bạn có thể vui lòng giải thích cho tôi lý do tại sao người ta có thể phá vỡ các quy tắc EDT nếu các thành phần là vô hình. Cảm ơn! – whomaniac

+0

@ user1155122 tôi đã thêm một mô tả trong câu trả lời vì nó quá lớn cho một bình luận duy nhất –

+0

Tôi đã googling trực tuyến như Mad và bạn là nguồn duy nhất đã cho tôi một số thông tin hữu ích thực tế về chủ đề. Cảm ơn!! – whomaniac

3

Có thể bạn đang cố gắng tạo hoạt ảnh sẽ được phát ngay khi bắt đầu ứng dụng của mình mà không ảnh hưởng đến các sự kiện hoặc thành phần sắp tới. Vì vậy, bạn có thể muốn thử xem màn hình giật gân. Đọc về nó từ đây: http://docs.oracle.com/javase/tutorial/uiswing/misc/splashscreen.html

Trong liên kết ở trên, nó thể hiện cách sử dụng của một lớp có tên là SplashScreen chỉ xuất phát từ lớp Khung. Vì vậy, cơ chế là như thế: bạn hiển thị một khung riêng biệt (màn hình giật gân, hình động của bạn đi ở đây) và sau một thời gian ứng dụng chính của bạn được khởi chạy.

+0

Tôi thực sự muốn sử dụng màn hình giật gân này! Tôi thực sự làm! Tuy nhiên, có một vấn đề nhỏ. Tôi muốn màn hình giật gân được xử lý khi tôi muốn nó sau khi phương thức main() thoát ra. Theo tài liệu, nó tự động thoát khi main() thoát! Làm thế nào tôi có thể vô hiệu hóa điều này. Bất kỳ ý tưởng? – whomaniac

+0

@ user1155122: Màn hình giật gân được cho là được xử lý khi main() tồn tại. Tất cả chính() là nghĩa vụ phải làm là bắt đầu chủ đề sự kiện gửi Swing, và sau đó thoát. –

1

'Lớp ImageIcon' cho phép bạn tải hoạt ảnh gif. Tôi tải hình ảnh với 'getResource()'. Để làm điều này, tôi thường sử dụng lớp URL để chuyển đường dẫn tệp. Đường dẫn không cần thiết trong máy từ xa vì URL tên có thể đề xuất.

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

đường dẫn sẽ là đường dẫn của gif bên trong thư mục lớp.

Tài liệu tham khảo: http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html#getresource

+0

vui lòng sửa: this.getClass(). GetResource (đường dẫn) –

Các vấn đề liên quan