我使用Java,Swing(窗口构建器)在Windows上开发了一个应用程序
单击按钮,我的应用程序将转到另一个类(FileManager.java
文件)以计算输入文件夹中的文件总数(同时progressBar
将处于不确定模式)。知道文件数后,设置progressBar
最大值。
然后我调用convertToXLS(fileMgr)
来读取每个文件的内容(1 kb),并在读取每个文件时更新progressBar
。
以下是代码:
public class xmlToXL {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
xmlToXL window = new xmlToXL();
window.frame.setVisible(true);
}
});
private void initialize() {
...... some UI code ........
btnConvertXmlTo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
preConvertToXLS();
Task task = new Task(folderPath.getText());
task.execute();
} catch (Exception e1) {
e1.printStackTrace();
}
}// end of actionPerformed method
}); // end of action listened
}//end of initialize
public void preConvertToXLS() { //method to set few UI properties
btnConvertXmlTo.setEnabled(false);
progressBar.setVisible(true);
progressBar.setStringPainted(true);
progressBar.setIndeterminate(true);
progressBar.setString("Calculating Total number of files...");
progressBar.setForeground(new Color(0, 102, 0));
}
ParserUtils parUtils = new ParserUtils(); //class to parse XML files (in another .java file)
private void convertToXLS(FileManager fileMgr) {
try {
int i=1;
parUtils.reset();
progressBar.setValue(0);
List<File> files = fileMgr.getFiles();
for(File file : files) {
progressBar.setString("Reading " + i+ " of " + fileMgr.getSize()+ " files");
parUtils.parseFileUsingDOM(file); // This will read content of the input file
progressBar.setValue(i++);
}
btnConvertXmlTo.setEnabled(true);
} catch (Exception e) {
}
}
class Task extends SwingWorker<Void, Void> {
private FileManager fileMgr;
public Task(String srcPath) {
this.fileMgr = new FileManager(new File(srcPath));
}
/*
* Main task. Executed in background thread.
*/
@Override
public Void doInBackground() {
try {
progressBar.setIndeterminate(true);
fileMgr.readFiles();
progressBar.setIndeterminate(false);
progressBar.setMaximum(fileMgr.getSize());
convertToXLS(fileMgr);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/*
* Executed in event dispatching thread
*/
@Override
public void done() {
Toolkit.getDefaultToolkit().beep();
try {
progressBar.setString("FileRead Successful");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}//end of task class
}//end of My class
我的用户界面在fileMgr.readFiles();
后变得无法响应。它需要一两分钟,有时三分钟,然后执行convertToXLS(fileMgr)
。
FileManager.java
import XMLParsing.DetermineEncoding;
public class FileManager {
public HashMap<String, ArrayList<String>> dirFiles = null;
public ArrayList<String> dirNames = null;
public int numberOfFiles;
private File src;
private List<File> files;
public FileManager(File src) {
this.src = src;
dirNames = new ArrayList<String>();
dirFiles = new HashMap<String, ArrayList<String>>();
numberOfFiles = 0;
files = new ArrayList<File>();
}
public int getSize() {
return numberOfFiles;
}
public ArrayList<String> getDirectories(){
return dirNames;
}
public List<File> getFiles() {
Iterator it = dirFiles.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
String folderName = (pair.getKey()).toString();
ArrayList<String> FileNames = (ArrayList<String>) pair.getValue();
if (FileNames != null) {
for (String fileName : FileNames) {
if(replaceSelected(fileName)) {
File fXmlFile = new File(fileName);
files.add(fXmlFile);
}
else {
}
}
}
}
return files;
}
public void readFiles() throws IOException {
readFiles(src);
}
private void readFiles(File folder) throws IOException {
if (folder.isDirectory()) {
ArrayList<String> fileNames = new ArrayList<String>();
for (final File file : folder.listFiles()) {
if (file.isDirectory()) {
readFiles(file);
} else {
String fileName = (file.getPath()).toString();
if(fileName.toLowerCase().endsWith(".xml")) {
fileNames.add(file.getPath());
numberOfFiles = numberOfFiles + 1;
System.out.println(".");
if(!dirNames.contains(file.getParentFile().getName()))
dirNames.add(file.getParentFile().getName());
}
}
}
dirFiles.put(folder.getName(), fileNames);
}
}
private boolean replaceSelected(String filePath) {
String line;
String input = "";
try {
DetermineEncoding DE = new DetermineEncoding();
String encoding = DE.getFileEncoding(filePath);
InputStreamReader file = new InputStreamReader(new FileInputStream(
filePath), encoding);
BufferedReader br = new BufferedReader(file);
while ((line = br.readLine()) != null) {
input += line.toString() + " ";
}
file.close();
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(filePath), "UTF-8"));
out.append(input.trim());
out.flush();
out.close();
} catch (Exception e) {
return false;
}
return true;
}
}
DetermineEncoding.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.mozilla.universalchardet.UniversalDetector;
public class DetermineEncoding {
public DetermineEncoding() {
// TODO Auto-generated constructor stub
}
public String getFileEncoding(String fileName) throws IOException {
byte[] buf = new byte[4096];
java.io.FileInputStream fis = new FileInputStream(fileName);
UniversalDetector detector = new UniversalDetector(null);
int nread;
while ((nread = fis.read(buf)) > 0 && !detector.isDone()) {
detector.handleData(buf, 0, nread);
}
detector.dataEnd();
String encoding = detector.getDetectedCharset();
if (encoding != null) {
return encoding;
} else {
return "";
}
}
}
请帮我确定问题。
答案 0 :(得分:3)
基本问题是感知问题。你“认为”UI没有响应,事实上,它只是在等待。
当您致电readFiles
时,它会检查您之前扫描过的所有文件,读取它们然后再将它们写出来,同时进度条处于“确定”模式,因此它不会显示任何内容。
您需要的是FileManager
向您的工作人员提供有关其进度的更新的一些方法,但工作人员会通过许多其他方法,这些方法也必须提供进度通知。
这似乎暗示了某种Observer Pattern的需要,当某些事情发生变化时,工作人员可以通过该计划的其他部分获知。
我们还需要以允许使用安全更新UI的方式完成所有这些工作
让我们从观察者开始......
public interface ProgressListener {
public void progressChanged(double progress);
public void setStatus(String text);
}
非常简单,当状态改变时,它会通知您,允许谁正在听取他们认为合适的更新。
基本进度值介于0-1之间,这意味着监听器实际上并不关心您拥有多少值,它只关心您的进度,这样就无需尝试更新进度条关于它的最大值而只需关注在0-100之间更新进度条的需要
现在我们需要在API的其余部分为它提供空间
private void convertToXLS(FileManager fileMgr, ProgressListener listener) {
try {
int i = 1;
listener.progressChanged(0d);
List<File> files = fileMgr.getFiles(listener);
for (File file : files) {
listener.setStatus("Reading " + i + " of " + fileMgr.getSize() + " files");
parUtils.parseFileUsingDOM(file); // This will read content of the input file
listener.progressChanged(i / (double) files.size());
}
btnConvertXmlTo.setEnabled(true);
} catch (Exception e) {
e.printStackTrace();
}
}
FileManager#getFiles
....
public List<File> getFiles(ProgressListener listener) {
Iterator it = dirFiles.entrySet().iterator();
int count = dirFiles.size();
for (Map.Entry<String, ArrayList<String>> entry : dirFiles.entrySet()){
count += entry.getValue() == null ? 0 : entry.getValue().size();
}
int index = 0;
listener.setStatus("Processing files...");
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
String folderName = (pair.getKey()).toString();
ArrayList<String> FileNames = (ArrayList<String>) pair.getValue();
if (FileNames != null) {
for (String fileName : FileNames) {
if (replaceSelected(fileName)) {
File fXmlFile = new File(fileName);
files.add(fXmlFile);
} else {
}
index++;
listener.progressChanged(index / (double)count);
}
}
}
return files;
}
接下来,我们需要更新Task
以利用它的进度支持,我们还需要允许更改进度条的状态。
我们可以通过publish
/ process
方法将消息从后台线程发送到EDT。我们还可以“欺骗”一点并使用它来发送消息以更改进度条的indeterminate
状态(fyi:您也可以使用属性更改侦听器支持来执行此操作,这可能是一个更清洁的方法)
class Task extends SwingWorker<Void, String> {
protected static final String INDETERMINATE_ON = "indeterminate.on";
protected static final String INDETERMINATE_OFF = "indeterminate.off";
private FileManager fileMgr;
public Task(String srcPath) {
this.fileMgr = new FileManager(new File(srcPath));
}
@Override
protected void process(List<String> chunks) {
for (String text : chunks) {
if (INDETERMINATE_OFF.equals(text)) {
progressBar.setIndeterminate(false);
} else if (INDETERMINATE_ON.equals(text)) {
progressBar.setIndeterminate(true);
} else {
progressBar.setString(text);
}
}
}
/*
* Main task. Executed in background thread.
*/
@Override
public Void doInBackground() {
try {
publish(INDETERMINATE_ON);
fileMgr.readFiles();
publish(INDETERMINATE_OFF);
convertToXLS(fileMgr, new ProgressListener() {
@Override
public void progressChanged(double progress) {
setProgress((int) (progress * 100d));
}
@Override
public void setStatus(String text) {
publish(text);
}
});
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/*
* Executed in event dispatching thread
*/
@Override
public void done() {
Toolkit.getDefaultToolkit().beep();
try {
progressBar.setString("FileRead Successful");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}//end of task class
最后,我们需要在创建PropertyChangeListener
时向Task
添加progress
,这样我们就可以获得task.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
switch (name) {
case "progress":
int value = (int) evt.getNewValue();
progressBar.setValue(value);
break;
}
}
});
更新并更新进度条......
struts.xml
简单:P
答案 1 :(得分:0)
代码似乎很好。我似乎无法检查的唯一事情是FileManager。使用FileReader,它在一个单独的线程中运行,允许用户同时操作。所以我猜FileManager必定会导致问题。