#java #swing
#java #swing
Вопрос:
Я хочу создать загрузочное сообщение, которое будет появляться на экране во время загрузки информации. Я вызову для него метод initLoadingPanel(), чтобы JFrame был виден. Моя проблема в том, как я могу ее закрыть?
Мой код приведен ниже.
public class DataMigration extends JFrame{
private JFrame frmDataMigration;
private JFrame loader;
private JButton btnProcess;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
DataMigration window = new DataMigration();
window.frmDataMigration.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public DataMigration() {
initialize();
}
private void initialize() {
LoggerImp.startLog(CLASS_NAME, "initialize()");
frmDataMigration = new JFrame();
btnProcess = new JButton("Load");
btnProcess.setEnabled(false);
btnProcess.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
SwingWorker <CSV, CSV> worker = new SwingWorker<CSV, CSV>() {
@Override
protected CSV doInBackground() throws Exception {
return FileReaderCSVHelper.fileReader(dirName.getText(), fileName.getText());
}
@Override
protected void done() {
try {
csv = doInBackground();
generateTableList(csv.getCsvTitle(), stateController.getFieldNames());
} catch (ExecutionException ex) {
ex.printStackTrace();
} catch (Exception e){
}
loader.dispose();
}
};
worker.execute();
}
});
frmDataMigration.getContentPane().add(btnProcess);
}
public void initLoadingPanel(){
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
loader = new JFrame("Loading....");
ImageIcon img = new ImageIcon("loader.gif");
loader.add(new JLabel(" Loading...", img, JLabel.CENTER));
loader.setAlwaysOnTop(true);
loader.pack();
loader.setSize( 448, 497);
loader.setVisible(true);
loader.setLocationRelativeTo(null);
}
});
}
Ответ №1:
Как правило, вам нужно только вызвать loader.dispose()
or loader.setVisible(false)
, тогда возникает вопрос о том, как вы загружаете свои ресурсы?
Вероятно, вам потребуется передать ссылку loader
на эту часть вашего кода, чтобы, когда она будет завершена, вы могли избавиться от фрейма.
Поскольку рамка оформлена, пользователь может просто нажать кнопку «[x]» и закрыть окно, в то время как вы можете установить рамки defaultCloseOperation
DO_NOTHING_ON_CLOSE
, это все равно выглядит странно.
Вы могли бы удалить оформление фрейма с помощью JFrame#setUndecorated
Поскольку loader
extends from JFrame
по-прежнему позволяет пользователю взаимодействовать с родительским окном (если оно видно), лучшим решением может быть использование a JDialog
вместо и сделать его модальным.
Вы также можете рассмотреть вопрос о том, как создать заставку для некоторых других идей
Обновлено
Вы затеняете свои переменные…
Сначала вы объявляете loader
в качестве поля экземпляра DataMigration
public class DataMigration extends JFrame{
//...
private JFrame loader;
Но затем повторно объявите его в run
вашем методе Runnable
….
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame loader = new JFrame("Loading....");
Это означает, что поле экземпляра по-прежнему равно нулю, попробуйте…
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
loader = new JFrame("Loading....");
вместо этого…
Также…
public void actionPerformed(ActionEvent arg0) {
initLoadingPanel();
csv = FileReaderCSVHelper.fileReader(dirName.getText(), fileName.getText());
generateTableList(csv.getCsvTitle(), stateController.getFieldNames());
loader.dispose();
}
Не собирается делать то, что, по вашему мнению, должно … вам «может» повезти, и loader
появится фрейм, но, скорее всего, этого не произойдет, потому что вы блокируете поток отправки событий.
Вместо этого вам следует рассмотреть возможность использования SwingWorker
….
initLoadingPanel();
SwingWorker worker = new SwingWorker<CVS, CVS>() {
@Override
protected CVS doInBackground() throws Exception {
return FileReaderCSVHelper.fileReader(dirName.getText(), fileName.getText());
}
@Override
protected void done() {
try {
cvs = get();
generateTableList(csv.getCsvTitle(), stateController.getFieldNames());
} catch (ExecutionException ex) {
ex.printStackTrace();
}
loader.dispose();
}
};
worker.execute();
(Я не знаю, что это за тип cvs
, поэтому я предполагаю…
Это гарантирует, что ваш пользовательский интерфейс будет оставаться отзывчивым во время загрузки данных…
Взгляните на параллелизм в Swing
Обновление с рабочим примером….
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;
public class DataMigration extends JFrame {
private JFrame frmDataMigration;
private JFrame loader;
private JButton btnProcess;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
DataMigration window = new DataMigration();
window.frmDataMigration.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public DataMigration() {
initialize();
}
private void initialize() {
frmDataMigration = new JFrame();
btnProcess = new JButton("Load");
btnProcess.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
initLoadingPanel();
SwingWorker worker = new SwingWorker() {
@Override
protected Object doInBackground() throws Exception {
Thread.sleep(5000);
return "This is a test value used to highlight the example";
}
@Override
protected void done() {
try {
get();
} catch (ExecutionException ex) {
} catch (InterruptedException ex) {
}
loader.dispose();
btnProcess.setEnabled(true);
}
};
worker.execute();
btnProcess.setEnabled(false);
}
});
frmDataMigration.getContentPane().add(btnProcess);
frmDataMigration.setDefaultCloseOperation(EXIT_ON_CLOSE);
frmDataMigration.pack();
frmDataMigration.setLocationRelativeTo(null);
}
public void initLoadingPanel() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
loader = new JFrame("Loading....");
ImageIcon img = new ImageIcon("loader.gif");
loader.add(new JLabel(" Loading...", img, JLabel.CENTER));
loader.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
loader.setAlwaysOnTop(true);
loader.pack();
loader.setSize(448, 497);
loader.setVisible(true);
loader.setLocationRelativeTo(null);
}
});
}
}
Комментарии:
1. Я сталкиваюсь со следующей ошибкой при вызове исключения loader.dispose() в потоке «AWT-EventQueue-0» java.lang. Исключение NullPointerException
2. Это (предположительно) потому, что вы объявили
loader
в локальном контексте внутриrun
метода. ВместоJFrame loader = new JFrame("Loading....");
этого вы могли бы попробоватьloader = new JFrame("Loading....");
, предполагая, чтоloader
это объявлено как переменная экземпляра. Также обратите внимание, что вы также должны вызыватьdispose
в контексте EDT3. Привет, я обновил свой код в соответствии с вашим предложением, но я все еще сталкиваюсь с ошибкой в строке loader.dispose()
4. Я сделал простой, доступный для выполнения пример (у меня нет вашего резюме, поэтому я его подделал)