Как обновить / раскрасить JProgressBar при загрузке Swing, создавая графический интерфейс - PullRequest
5 голосов
/ 16 августа 2011

У меня есть графический интерфейс, который довольно тяжело построить / инициализировать на платформе, на которой он работает. Поэтому я хочу обновить прогресс, пока он инициализируется.

У меня есть небольшой недекорированный JDialog, содержащий JLabelи JProgressBar, который я хочу обновить в определенных местах во время инициализации, однако, так как theadatch thead thead (согласно правилам Swing) используется для построения / инициализации GUI, прогресс, конечно, не обновляется до тех пор, пока EDT снова не будет свободен (т.е. инициализация завершена) ..

JProgressBar Я перерисовал с помощью «paintImmediately», но я не могу заставить его работать должным образом для JLabel и самого диалога. Есть ли какой-нибудь простой рекомендуемый/ проверенный метод для достижения этой цели?

ура ...

РЕДАКТИРОВАТЬ: Добавление примера того, что я пытаюсь сделать;конечно, значительно упростит.

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

        }
    });
}

перерисовки, вызванные вызовами к progressBar.setValue() / progressLabel.setText() выше, будут, конечно, поставлены в очередь, пока EDT занят и приведут к перекрашиванию после того, как мывсе сделано вместо обновления по пути ..

Ответы [ 4 ]

3 голосов
/ 16 августа 2011

Я хотел бы предложить, используя SwingWorker , тогда вы можете корректно обновить JProgressBar на EDT и без каких-либо заморозок или проблем с Конкуренцией в Swing ,

тамэто еще один вариант с использованием Runnable#thread, но тогда вам нужно перенести весь вывод в графический интерфейс в invokeLater();

, например:

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

РЕДАКТИРОВАТЬ:

1) у вас возникли другие проблемы: почему вы создаете много контейнеров верхнего уровня на лету / время выполнения, создаете только необходимое количество контейнеров и используете их повторно removeAll()

2) здесь это, вероятно, то, что вам нужно, все эти JProgressBars в JTable довольно доступны и настраиваются

3) это ваша paintImmediately () , это действительно причина, почему не рисовать любой из Progress в JLabel , а использовать JProgressBar#setValue(int); вместо

2 голосов
/ 16 августа 2011

Возможно, что constructSome*HeavyGUI() действительно занимает достаточно много времени, но больше вероятно, что проблема заключается в заполнении модели данных.Вместо этого создайте и покажите пустые элементы GUI и запустите один или несколько экземпляров SwingWorker, чтобы упорядочить данные каждого элемента.Есть соответствующие примеры здесь и здесь .

Приложение: Если проблема заключается в создании экземпляров компонентов, а не в загрузке моделей данных, вы можете связать вызовы с invokeLater(), как предлагается в комментарии ниже.Если вы создаете таких многих компонентов, рассмотрите шаблон flyweight .JTable является знакомым примером.

2 голосов
/ 16 августа 2011

Либо используйте SwingUtilities.invokeLater(...), как предложено @ StanislavL , либо используйте SwingWorker .

См. Также:

2 голосов
/ 16 августа 2011

Переместите долгосрочный код в отдельный поток и используйте SwingUtilities.invokeAndWait или invokeLater для обновления графического интерфейса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...