Пользовательский экран-заставка Java «зависает» до тех пор, пока не будет загружено все приложение - PullRequest
5 голосов
/ 01 марта 2010

У меня есть программа, которая долго загружается. Из-за этого я хотел разработать заставку, которая могла бы предоставлять обратную связь пользователю о том, что загружается. Простой JFrame с изображением, меткой и JProgressBar.

Я экспериментировал, и лучшие результаты, которые у меня были, достигаются в моем main():

SwingUtilities.invokeAndWait(new Runnable() {

    public void run() {

        new SplashScreen();
    }
});

SwingUtilities.invokeAndWait(new Runnable() {

    public void run() {

        //Code to start system
        new MainFrame();
        //.. etc
    }
});

И SplashScreen, и MainFrame являются классами, расширяющими JFrame. Я также использую вещество в качестве библиотеки.

Конструктор SplashScreen добавляет JLabel и JProgressBar к себе, упаковывает и устанавливает видимые. JProgressBar - setIndeterminate(true);

Когда я запускаю свою программу, отображается мой SplashScreen, но ProgressBar заблокирован, он не двигается, пока не запустится остальная часть программы, и он не начнет двигаться, как ожидалось.

Что мне здесь не хватает? Похоже, что во всех поисках, которые я выполнял, эта проблема не упоминается, и большинство реализаций "пользовательского заставки" делают это очень похоже на меня.

Ответы [ 4 ]

3 голосов
/ 01 марта 2010

Просто попытаться быть более общим, чем правильный ответ Аллена.

В вашей системе есть один поток, который (законно) может обновлять графические интерфейсы.

Если вы используете этот поток для инициализации вашей системы, guis НЕ будет обновляться.

Если вы пытаетесь обновить графический интерфейс из основного потока, ничего не получится.

Всегда помните, в каком потоке работает ваш графический интерфейс, и не выполняйте работу в этом потоке.

Думайте об обновлениях графического интерфейса следующим образом:

  • ваш поток без графического интерфейса обновляет отображаемое вами значение (например, процент выполнения).
  • отправляет обновление через invokeLater, затем продолжает другую работу.
  • Поток GUI выполняет ваш invokeLater, который обновляет ваш GUI данными, переданными из потока не-GUI
  • поток GUI, который он выходит! Это позволяет другим несвязанным частям системы обновлять графический интерфейс в случае необходимости.

Потоки, не относящиеся к графическому интерфейсу, чаще всего являются потоками из Thread.start, а потоки, переданные "main"

Поток GUI - это тот, который выполняет ваш invokeLater и все, что передается вам из события GUI (нажатие кнопки, таймер GUI, любые слушатели Swing.)

Из-за этого чаще всего вы уже находитесь в потоке графического интерфейса, когда пришло время обновлять графический интерфейс - просто следите за порядком запуска и местами, где потоки хотят обновить отображение.

3 голосов
/ 01 марта 2010

invokeAndWait остановит поток Swing до тех пор, пока заданная операция не завершится. Таким образом, ваш индикатор выполнения будет равен 100% до тех пор, пока не будет создан MainFrame.

Вы должны создать не качающуюся нить, которая обновляет заставку, используя SwingUtilities.invoke (Later | AndWait).

new Thread(new Runnable() { public void run() {
  // Create MainFrame here
  SwingUtilities.invokeLater(new Runnable() {
      public void run() {
         updateProgressHere();
      }
  });

  // Do other initialization
  SwingUtilities.invokeLater(new Runnable() {
      public void run() {
         updateProgressHere();
      }
  });
}).start(); 
1 голос
/ 02 марта 2010

Другие ответы охватили большую часть этого, но вкратце ваша проблема заключается в том, что вы запускаете «Код для запуска системы» в потоке рассылки событий Swing. Весь код, связанный с GUI (включая создание компонента) должен выполняться на EDT, но весь другой код не должен выполняться на EDT. Попробуйте изменить свою программу, чтобы сделать это:

SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        new SplashScreen();
    }
});
// Code to start system (nothing that touches the GUI)
SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        new MainFrame();
    }
});
//.. etc
1 голос
/ 01 марта 2010

Другие упоминают, почему ваш индикатор выполнения заблокирован. Я предложу альтернативное решение. В Java6 встроена обработка заставки, встроенная в для javaw и java launchers ...

Заставка отображается еще до загрузки JVM и классов приложения, а затем, после запуска, приложение может обновить его, чтобы отразить свое внутреннее состояние загрузки, и закрыть его, когда будет готово.

В качестве альтернативы для решений только для Windows, Java-пусковая установка *1007* Winrun4J также имеет функцию заставки.

...