1

グローバル読み込みダイアログを実装しようとしています...ダイアログを表示する静的関数と、ダイアログを閉じる静的関数を呼び出したいです。その間、私はメインスレッドまたはサブスレッドでいくつかの作業を行っています...

フォローしてみましたが、ダイアログが更新されていません...最後に一度だけ、もう一度非表示にする前に更新します...

    private static Runnable getLoadingRunable()
{
    if (loadingRunnable != null)
    {
        loadingFrame.setLocationRelativeTo(null);
        loadingFrame.setVisible(true);  
        return loadingRunnable;
    }

    loadingFrame = new JFrame("Updating...");
    final JProgressBar progressBar = new JProgressBar();
    progressBar.setIndeterminate(true);
    final JPanel contentPane = new JPanel();
    contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    contentPane.setLayout(new BorderLayout());
    contentPane.add(new JLabel("Updating..."), BorderLayout.NORTH);
    contentPane.add(progressBar, BorderLayout.CENTER);
    loadingFrame.setContentPane(contentPane);
    loadingFrame.pack();
    loadingFrame.setLocationRelativeTo(null);
    loadingFrame.setVisible(true);  

    loadingRunnable = new Runnable() {
        public void run() {

            try {
                while (running) {
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    loadingFrame.setVisible(false);
                }
            });
        }
    };
    return loadingRunnable;
}

public static void showLoadingBar() {
    System.out.println("showLoadingBar");
    running = true;

    threadLoadingBar = new Thread(getLoadingRunable());
    threadLoadingBar.start();
}

public static void hideLoadingBar() {
    System.out.println("hideLoadingBar");
    running = false;
    threadLoadingBar = null;
}
4

2 に答える 2

8

Swing は、イベントのディスパッチ (ペイントの更新を含む) にシングル スレッド モデルを使用するため、イベント ディスパッチ スレッド (EDT) 内で実行時間の長い操作やブロック操作を絶対に実行しないでください。

また、Swing はスレッド セーフではありません。つまり、EDT の外部から UI コンポーネントを作成または変更しないでください。

グローバル進行状況ダイアログの基本的な概念は、実行する必要がある作業に依存しないフレームワークを提供することです。これにより、責任の領域が分離され、進行状況の表示を担当する進行状況ダイアログと、作業を担当するワーカー/エンジンが分離されます。実際の作業を行っています。

最も簡単な解決策は、SwingWorker. これにより、個別のスレッドで長時間実行されるタスクを実行するためのメカニズム、状態の変更、および進行状況の通知が提供されます。

ここに画像の説明を入力

public class TestProgressDialog {

    public static void main(String[] args) {
        new TestProgressDialog();
    }

    public TestProgressDialog() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                SwingWorker worker = new SwingWorker() {
                    @Override
                    protected Object doInBackground() throws Exception {
                        for (int index = 0; index < 100; index++) {
                            Thread.sleep(50);
                            setProgress(index);
                        }
                        return null;
                    }

                };

                ProgressDialog.showProgress(null, worker);

                System.exit(0);

            }

        });
    }

    public static class ProgressDialog extends JDialog {

        private JLabel message;
        private JLabel subMessage;
        private JProgressBar progressBar;

        public ProgressDialog(Component parent, SwingWorker worker) {

            super(parent == null ? null : SwingUtilities.getWindowAncestor(parent));
            setModal(true);

            ((JComponent)getContentPane()).setBorder(new EmptyBorder(8, 8, 8, 8));

            message = new JLabel("Doing important stuff");
            subMessage = new JLabel("Go make you're self a cup of coffee...");
            progressBar = new JProgressBar();

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(2, 2, 2, 2);
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.WEST;
            add(message, gbc);

            gbc.gridy++;
            add(subMessage, gbc);

            gbc.gridy++;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            add(progressBar, gbc);

            pack();

            worker.addPropertyChangeListener(new PropertyChangeHandler());
            switch (worker.getState()) {
                case PENDING:
                    worker.execute();
                    break;
            }

        }

        public static void showProgress(Component parent, SwingWorker worker) {

            ProgressDialog dialog = new ProgressDialog(parent, worker);
            dialog.setLocationRelativeTo(parent);
            dialog.setVisible(true);

        }

        public class PropertyChangeHandler implements PropertyChangeListener {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equals("state")) {
                    SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
                    switch (state) {
                        case DONE:
                            dispose();
                            break;
                    }
                } else if (evt.getPropertyName().equals("progress")) {
                    progressBar.setValue((int)evt.getNewValue());
                }
            }

        }

    }

}
于 2013-01-01T22:04:50.203 に答える
5

アニメーションしない場合は、ロード フレームが表示されている間にイベント ディスパッチ スレッドで作業を行っていることを意味します。このバックグラウンド作業は別のスレッドで行う必要があります。

動作しない例を次に示します。

public static void main(String[] args) throws Exception {
    SwingUtilities.invokeLater(
        new Runnable() {
            @Override
            public void run() {
                try {
                    showLoadingBar();
                    Thread.sleep(10000L); // doing work in the EDT. Prevents the frame from animating
                    hideLoadingBar();
                }
                catch (InterruptedException e) {
                }
            }
        }
    );
}

これが実際の例です:

public static void main(String[] args) throws Exception {
    showLoadingBar();
    Thread.sleep(10000L); // doing work outside of the EDT. Everything works fine
    hideLoadingBar();
}

補足: ローディング フレームをインスタンス化し、設定し、可視化するコードSwingUtilities.invokeLater()は、EDT で実行する必要があるため、 にラップする必要があります。

于 2013-01-01T20:39:17.733 に答える