У меня есть программа, которая занимает много времени для загрузки. Из-за этого я хотел разработать экран-заставку, который может предоставить обратную связь пользователю на том, что загружается. Простой 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 заблокирован, это не перемещается, только когда остальная часть программы запустилась, делает это начинает перемещаться как ожидалось.
Что я пропускаю здесь? Весь поиск, который я сделал, кажется, не упоминает, что эта проблема и большая часть "пользовательского экрана-заставки" реализации идут об этом очень похожим путем ко мне.
Другие ответы охватили большую часть этого, но вкратце ваша проблема заключается в том, что вы запускаете «Код для запуска системы» в потоке отправки событий 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
Просто чтобы попытаться быть немного более общим, чем правильный ответ Аллена.
В вашей системе есть один поток, который может (легально) обновлять GUI.
Если вы используете этот поток для инициализации вашей системы, guis НЕ будет обновляться.
Если вы пытаетесь обновить графический интерфейс из основного потока, ничего не получится.
Всегда помните, в каком потоке работает ваш графический интерфейс, и убедитесь, что не выполняете никаких действий в этом потоке.
Думайте об обновлениях графического интерфейса следующим образом:
Потоки, не относящиеся к графическому интерфейсу, чаще всего являются потоками из Thread.start, а потоки передаются в "main"
Поток графического интерфейса - это поток, выполняющий ваш invokeLater и все, что передается вам из события графического интерфейса (кнопка нажата, Таймер графического интерфейса пользователя, любые прослушиватели Swing.)
Из-за этого чаще всего вы уже находитесь в потоке графического интерфейса, когда пришло время обновить графический интерфейс - просто следите за порядком запуска и местами, где потоки хотят обновить отображение.
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();
Другие упомянули, почему ваш индикатор выполнения заблокирован, я предложу альтернативное решение В Java6 встроена обработка заставки в javaw и java launchers...
Заставка отображается еще до загрузки JVM и классов приложения, а после запуска приложение может обновить ее, чтобы отразить свое внутреннее состояние загрузки, и закрыть ее, когда она будет готова.
В качестве альтернативы, для решений только для windows, Winrun4J java launcher также имеет функцию заставки.