2011-08-16 35 views
5

Tôi có một GUI khá nặng để xây dựng/khởi tạo trên nền tảng mà nó chạy .. Vì vậy, tôi muốn cập nhật tiến trình trong khi nó khởi tạo ..Làm thế nào để cập nhật/vẽ JProgressBar trong khi Swing được tải xây dựng GUI

Tôi có một JDialog nhỏ chưa được trang bị chứa một JLabel và một JProgressBar mà tôi muốn cập nhật tại những vị trí cụ thể trong quá trình khởi tạo, bởi vì sự kiện gửi đi (theo quy tắc Swing) được sử dụng để xây dựng/khởi tạo GUI, tiến trình là tất nhiên là không được cập nhật cho đến khi EDT không hoạt động nữa (tức là khởi tạo xong) ..

JProgressBar Tôi đã vẽ lại bằng cách sử dụng "paintImmediately", nhưng tôi dường như không làm cho nó hoạt động tốt cho t JLabel và hộp thoại chính nó .. Có phương pháp nào được đề nghị/chứng minh đơn giản để thực hiện việc này không?

cổ vũ ...

EDIT: Thêm ví dụ về nội dung tôi đang cố gắng thực hiện; rất đơn giản, tất nhiên.

private JLabel progressLabel; 
private JProgressBar progressBar; 

public static int main(String[] args) { 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      showProgressDialog(); 
      progressLabel.setText("construct 1"); 

      constructSomeHeavyGUI(); 

      progressLabel.setText("construct 2"); 
      progressBar.setValue(33); 

      constructSomeMoreHeavyGUI(); 

      progressLabel.setText("construct 3"); 
      progressBar.setValue(67); 

      constructEvenMoreHeavyGUI(); 

      progressLabel.setText("done"); 
      progressBar.setValue(100); 

      hideProgressDialog(); 

      showHeavyGUI(); 

     } 
    }); 
} 

các repaints do các cuộc gọi đến progressBar.setValue()/progressLabel.setText() trên tất nhiên sẽ được xếp hàng đợi chừng nào EDT đang bận và kết quả là một repaint sau khi chúng tôi đều thực hiện thay vì cập nhật trên đường đi ..

+1

* "đơn giản hóa rất nhiều, tất nhiên" * Để đăng mã được đơn giản hóa rất nhiều cho người trả lời, hãy đăng [SSCCE] (http://pscode.org/sscce.html) (tất nhiên). –

Trả lời

2

Có thể là constructSome*HeavyGUI() thực sự có đủ thời gian để quan trọng, nhưng nó hơn khả năng điền vào (các) mô hình dữ liệu là vấn đề.Thay vào đó, hãy xây dựng và hiển thị các phần tử GUI trống và khởi chạy một hoặc nhiều trường hợp SwingWorker để so sánh dữ liệu của từng phần tử. Có các ví dụ liên quan herehere.

Phụ lục: Nếu sự cố là khởi tạo thành phần và không tải mô hình dữ liệu, bạn có thể chuỗi các cuộc gọi đến invokeLater(), như được đề xuất trong nhận xét bên dưới. Nếu bạn đang instantiating rằng nhiều thành phần, hãy xem xét flyweight pattern. JTable là một ví dụ quen thuộc.

+0

nó không phổ biến nó với dữ liệu gây ra vấn đề, vì không có dữ liệu được lấy/dân cư trong khi xây dựng. –

+0

Tôi không thấy điều đó. Nếu bạn không thể tải bất cứ thứ gì, bạn sẽ phải gọi các chuỗi đến 'invokeLater()'. Ví dụ, hãy để 'constructHeavy1()' kết thúc bằng một 'invokeLater()' của 'constructHeavy2()', v.v. – trashgod

+0

có, đó sẽ là một khả năng, mặc dù một sự khó xử, tôi đoán .. –

2

Di chuyển mã chạy dài trong một chuỗi riêng biệt và sử dụng SwingUtilities.invokeAndWait hoặc invokeLater để cập nhật GUI.

3

tôi sẽ đề nghị rằng bằng cách sử dụng SwingWorker, sau đó bạn có thể cập nhật JProgressBar chính xác trên EDT và không có bất kỳ đóng băng hoặc isuees với Concurency in Swing,

có một tùy chọn khác bằng cách sử dụng Runnable#thread, nhưng sau đó bạn phải bao bọc tất cả đầu ra cho GUI thành invokeLater();

ví dụ:

import java.awt.Dimension; 
import java.awt.Toolkit; 
import java.awt.Window; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 

import javax.swing.*; 

public class TestProgressBar { 

    private static void createAndShowUI() { 
     JFrame frame = new JFrame("TestProgressBar"); 
     frame.getContentPane().add(new TestPBGui().getMainPanel()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       createAndShowUI(); 
      } 
     }); 
    } 

    private TestProgressBar() { 
    } 
} 

class TestPBGui { 

    private JPanel mainPanel = new JPanel(); 

    public TestPBGui() { 
     JButton yourAttempt = new JButton("WRONG attempt to show Progress Bar"); 
     JButton myAttempt = new JButton("BETTER attempt to show Progress Bar"); 
     yourAttempt.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       yourAttemptActionPerformed(); 
      } 
     }); 
     myAttempt.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       myAttemptActionPerformed(); 
      } 
     }); 
     mainPanel.add(yourAttempt); 
     mainPanel.add(myAttempt); 
    } 

    private void yourAttemptActionPerformed() { 
     Window thisWin = SwingUtilities.getWindowAncestor(mainPanel); 
     JDialog progressDialog = new JDialog(thisWin, "Uploading..."); 
     JPanel contentPane = new JPanel(); 
     contentPane.setPreferredSize(new Dimension(300, 100)); 
     JProgressBar bar = new JProgressBar(0, 100); 
     bar.setIndeterminate(true); 
     contentPane.add(bar); 
     progressDialog.setContentPane(contentPane); 
     progressDialog.pack(); 
     progressDialog.setLocationRelativeTo(null); 
     Task task = new Task("Your attempt"); 
     task.execute(); 
     progressDialog.setVisible(true); 
     while (!task.isDone()) { 
     } 
     progressDialog.dispose(); 
    } 

    private void myAttemptActionPerformed() { 
     Window thisWin = SwingUtilities.getWindowAncestor(mainPanel); 
     final JDialog progressDialog = new JDialog(thisWin, "Uploading..."); 
     JPanel contentPane = new JPanel(); 
     contentPane.setPreferredSize(new Dimension(300, 100)); 
     final JProgressBar bar = new JProgressBar(0, 100); 
     bar.setIndeterminate(true); 
     contentPane.add(bar); 
     progressDialog.setContentPane(contentPane); 
     progressDialog.pack(); 
     progressDialog.setLocationRelativeTo(null); 
     final Task task = new Task("My attempt"); 
     task.addPropertyChangeListener(new PropertyChangeListener() { 

      @Override 
      public void propertyChange(PropertyChangeEvent evt) { 
       if (evt.getPropertyName().equalsIgnoreCase("progress")) { 
        int progress = task.getProgress(); 
        if (progress == 0) { 
         bar.setIndeterminate(true); 
        } else { 
         bar.setIndeterminate(false); 
         bar.setValue(progress); 
         progressDialog.dispose(); 
        } 
       } 
      } 
     }); 
     task.execute(); 
     progressDialog.setVisible(true); 
    } 

    public JPanel getMainPanel() { 
     return mainPanel; 
    } 
} 

class Task extends SwingWorker<Void, Void> { 

    private static final long SLEEP_TIME = 4000; 
    private String text; 

    public Task(String text) { 
     this.text = text; 
    } 

    @Override 
    public Void doInBackground() { 
     setProgress(0); 
     try { 
      Thread.sleep(SLEEP_TIME);// imitate a long-running task 
     } catch (InterruptedException e) { 
     } 
     setProgress(100); 
     return null; 
    } 

    @Override 
    public void done() { 
     System.out.println(text + " is done"); 
     Toolkit.getDefaultToolkit().beep(); 
    } 
} 

EDIT: số

1), bạn cho thấy các vấn đề khác, tại sao bạn tạo nhiều Top-Level Container trên Fly/Runtime, tạo chỉ được yêu cầu của Container và tái -Sử dụng mà bởi removeAll()

2) here có lẽ là những gì bạn cần, tất cả những JProgressBars trong JTable là khá accesible và cấu hình

01.

3) đây là paintImmediately() của bạn, đó thực sự lý do tại sao không vẽ bất kỳ Progress đến JLabel nhưng sử dụng JProgressBar#setValue(int); thay vào đó,

+0

mà sẽ không hoạt động .. nếu bạn đọc bài đăng của tôi chặt chẽ, bạn sẽ nhận thấy rằng tôi nhận thức được tất cả các vấn đề luồng Swing/EDT .. Tôi không thể đặt mã chạy dài trên một chủ đề khác vì nó là GUI xây dựng mã, mà phải chạy trên EDT theo quy tắc Swing .. Những gì tôi sau khi thực sự là một cách ngay lập tức để (lại) vẽ hộp thoại tiến bộ của tôi trong khi tôi đã chạy trên EDT .. –

+0

1) xin vui lòng don Không sử dụng paintImmediately() cho Conompound JComponets, chỉ khi bạn có thể tạo giao diện người dùng cho một số JComponents, 2) bạn có thể cho thấy (sự tò mò của tôi) cách bạn thực hiện paintImmediately(), vì điều này có thể được sử dụng chỉ khi EDT tồn tại và bạn luôn luôn cần phải kiểm tra nếu (SwingUtilities.isEventDispatchThread()) 3) không reinvent bánh xe, JProgressbar có thể làm điều đó easilly bằng cách thực hiện các phương pháp – mKorbel

+0

1) ok, nhưng những gì tôi nên sử dụng sau đó? 2)/3) vui lòng xem bản chỉnh sửa trong bài đăng gốc của tôi để biết ví dụ. –

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