创建一个 'loading...' 动画帧以显示为正在执行的方法?
Creating a 'loading...' animation frame to display as a method is being executed?
我有一个 FileFinder.java 和一个带有 GUI 的 Loading.java class。 FileFinder.java 允许用户 select 目录并在该目录中搜索文件。现在,对于更大的目录,搜索需要一些时间才能完成,我不想让用户怀疑它是否真的在搜索,所以我试图显示另一个框架 (Loading.java)。
这是我在单击“搜索”按钮时的代码:
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String dirName = "";
String username = System.getProperty("user.name");
if(cdriveButton.isSelected()){
dirName = "C:/Users/" + username;
}
else if(pdriveButton.isSelected()){
dirName = "P:";
}
else if(xdriveButton.isSelected()){
dirName = "X:";
}
else if(customButton.isSelected()){
dirName = JOptionPane.showInputDialog(rootPane, "Enter the directory you would like to search in: ", "Enter Directory", HEIGHT);
}
String search = filenameText.getText();
File root = new File(dirName);
resultText.setText("");
Loading show = new Loading();
show.setVisible(true);
displayDirectoryContents(root, search);
show.setVisible(false);
}
这里是 Loading.java:
public class Loading extends javax.swing.JFrame {
/**
* Creates new form Loading
*/
public Loading() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jLabel1.setText("Please wait...");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(148, 148, 148)
.addComponent(jLabel1)
.addContainerGap(186, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(122, 122, 122)
.addComponent(jLabel1)
.addContainerGap(164, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(Loading.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(Loading.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(Loading.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Loading.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Loading().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
// End of variables declaration
}
一切正常,除了一个小问题:它没有在加载框架内正确显示 GUI。当我按下按钮时它会弹出,并一直保持到搜索完成,然后正确关闭,但它应该显示一个标签,上面写着 "Please wait..."。它没有显示该标签,它只显示一个空白的白色框。
Edit1:找到以下解决方案。转换为 JDialog 窗格而不是 JFrame 并添加一个 SwingWorker:
JDialog jDialog = new JDialog();
jDialog.setLayout(new GridBagLayout());
jDialog.add(new JLabel("Please wait..."));
jDialog.setMinimumSize(new Dimension(150, 50));
jDialog.setResizable(false);
jDialog.setModal(false);
jDialog.setUndecorated(true);
jDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
jDialog.setLocationRelativeTo(null);
jDialog.setVisible(true);
SwingWorker swingWorker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
displayDirectoryContents(root, search);
return null;
}
};
你的问题在这里:
displayDirectoryContents(root, search);
您 运行 在 Java 事件线程或 EDT(事件调度线程)上执行此操作。当 运行 花费的时间超过片刻时,它会阻止 EDT 并阻止它做它需要做的事情,包括显示你的加载 window(顺便说一句应该是一个 对话框 window 例如 JDialog 而 不是 应用程序 window 或 JFrame)。
解决方案:运行 此方法在后台线程中调用,例如 SwingWorker 提供的线程。显示您的 对话框 window,并在工作人员完成时使用回调通知您,因此您不应再显示加载对话框 window。
例如,这个:
String search = filenameText.getText();
File root = new File(dirName);
resultText.setText("");
Loading show = new Loading();
show.setVisible(true);
displayDirectoryContents(root, search);
show.setVisible(false);
可以更改为类似(注意代码未测试)
String search = filenameText.getText();
File root = new File(dirName);
resultText.setText("");
Loading show = new Loading();
show.setVisible(true);
// create our worker
new SwingWorker<Void, Void> worker = new SwingWorker<>(){
@Override
protected Void doInBackground() throws Exception {
displayDirectoryContents(root, search);
return null;
}
};
worker.addPropertyChangeListener(evt -> {
if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
// you should also call get() on the worker allowing
// you to capture and handle all exceptions it might throw
show.setVisible(false);
}
});
worker.execute(); // run the worker
你的问题的解决方法参考鳗鱼的@Hovercraft 回答
附带回答一下,使用多个 JFrames
是不好的做法,我建议您使用 JDialog。看这个例子:
JDialog jDialog = new JDialog();
jDialog.setLayout(new GridBagLayout());
jDialog.add(new JLabel("Please wait..."));
jDialog.setMinimumSize(new Dimension(150, 50));
jDialog.setResizable(false);
jDialog.setModal(false);
jDialog.setUndecorated(true);
jDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
jDialog.setLocationRelativeTo(null);
jDialog.setVisible(true);
这将在屏幕中央的灰色小框中显示消息 "Please wait...",没有关闭按钮或标题栏。
由于 setModal(false)
选项,它也是 non-blocking。因此其他代码可以在显示时执行。
我有一个 FileFinder.java 和一个带有 GUI 的 Loading.java class。 FileFinder.java 允许用户 select 目录并在该目录中搜索文件。现在,对于更大的目录,搜索需要一些时间才能完成,我不想让用户怀疑它是否真的在搜索,所以我试图显示另一个框架 (Loading.java)。
这是我在单击“搜索”按钮时的代码:
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String dirName = "";
String username = System.getProperty("user.name");
if(cdriveButton.isSelected()){
dirName = "C:/Users/" + username;
}
else if(pdriveButton.isSelected()){
dirName = "P:";
}
else if(xdriveButton.isSelected()){
dirName = "X:";
}
else if(customButton.isSelected()){
dirName = JOptionPane.showInputDialog(rootPane, "Enter the directory you would like to search in: ", "Enter Directory", HEIGHT);
}
String search = filenameText.getText();
File root = new File(dirName);
resultText.setText("");
Loading show = new Loading();
show.setVisible(true);
displayDirectoryContents(root, search);
show.setVisible(false);
}
这里是 Loading.java:
public class Loading extends javax.swing.JFrame {
/**
* Creates new form Loading
*/
public Loading() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jLabel1.setText("Please wait...");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(148, 148, 148)
.addComponent(jLabel1)
.addContainerGap(186, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(122, 122, 122)
.addComponent(jLabel1)
.addContainerGap(164, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(Loading.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(Loading.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(Loading.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Loading.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Loading().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
// End of variables declaration
}
一切正常,除了一个小问题:它没有在加载框架内正确显示 GUI。当我按下按钮时它会弹出,并一直保持到搜索完成,然后正确关闭,但它应该显示一个标签,上面写着 "Please wait..."。它没有显示该标签,它只显示一个空白的白色框。
Edit1:找到以下解决方案。转换为 JDialog 窗格而不是 JFrame 并添加一个 SwingWorker:
JDialog jDialog = new JDialog();
jDialog.setLayout(new GridBagLayout());
jDialog.add(new JLabel("Please wait..."));
jDialog.setMinimumSize(new Dimension(150, 50));
jDialog.setResizable(false);
jDialog.setModal(false);
jDialog.setUndecorated(true);
jDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
jDialog.setLocationRelativeTo(null);
jDialog.setVisible(true);
SwingWorker swingWorker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
displayDirectoryContents(root, search);
return null;
}
};
你的问题在这里:
displayDirectoryContents(root, search);
您 运行 在 Java 事件线程或 EDT(事件调度线程)上执行此操作。当 运行 花费的时间超过片刻时,它会阻止 EDT 并阻止它做它需要做的事情,包括显示你的加载 window(顺便说一句应该是一个 对话框 window 例如 JDialog 而 不是 应用程序 window 或 JFrame)。
解决方案:运行 此方法在后台线程中调用,例如 SwingWorker 提供的线程。显示您的 对话框 window,并在工作人员完成时使用回调通知您,因此您不应再显示加载对话框 window。
例如,这个:
String search = filenameText.getText();
File root = new File(dirName);
resultText.setText("");
Loading show = new Loading();
show.setVisible(true);
displayDirectoryContents(root, search);
show.setVisible(false);
可以更改为类似(注意代码未测试)
String search = filenameText.getText();
File root = new File(dirName);
resultText.setText("");
Loading show = new Loading();
show.setVisible(true);
// create our worker
new SwingWorker<Void, Void> worker = new SwingWorker<>(){
@Override
protected Void doInBackground() throws Exception {
displayDirectoryContents(root, search);
return null;
}
};
worker.addPropertyChangeListener(evt -> {
if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
// you should also call get() on the worker allowing
// you to capture and handle all exceptions it might throw
show.setVisible(false);
}
});
worker.execute(); // run the worker
你的问题的解决方法参考鳗鱼的@Hovercraft 回答
附带回答一下,使用多个 JFrames
是不好的做法,我建议您使用 JDialog。看这个例子:
JDialog jDialog = new JDialog();
jDialog.setLayout(new GridBagLayout());
jDialog.add(new JLabel("Please wait..."));
jDialog.setMinimumSize(new Dimension(150, 50));
jDialog.setResizable(false);
jDialog.setModal(false);
jDialog.setUndecorated(true);
jDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
jDialog.setLocationRelativeTo(null);
jDialog.setVisible(true);
这将在屏幕中央的灰色小框中显示消息 "Please wait...",没有关闭按钮或标题栏。
由于 setModal(false)
选项,它也是 non-blocking。因此其他代码可以在显示时执行。