Пользовательский экран-заставка Java “замораживания” до целого приложения загрузился

У меня есть программа, которая занимает много времени для загрузки. Из-за этого я хотел разработать экран-заставку, который может предоставить обратную связь пользователю на том, что загружается. Простой 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 заблокирован, это не перемещается, только когда остальная часть программы запустилась, делает это начинает перемещаться как ожидалось.

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

5
задан Abdul Rahman 22 October 2012 в 14:58
поделиться

4 ответа

Другие ответы охватили большую часть этого, но вкратце ваша проблема заключается в том, что вы запускаете «Код для запуска системы» в потоке отправки событий Swing. Весь код, связанный с графическим интерфейсом пользователя (включая создание компонентов) , должен запускаться на 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
ответ дан 14 December 2019 в 04:36
поделиться

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

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

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

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

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

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

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

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

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

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

3
ответ дан 14 December 2019 в 04:36
поделиться

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

Вы должны породить не Swing-поток, который обновляет Splash Screen, используя 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(); 
3
ответ дан 14 December 2019 в 04:36
поделиться

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

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

В качестве альтернативы, для решений только для windows, Winrun4J java launcher также имеет функцию заставки.

1
ответ дан 14 December 2019 в 04:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: