基本上,我有两个类:1表示将JProgressBar添加到JPanel的GUI,另一个是具有JProgressBar应该更新的进程的类。
我的问题是进度条不会定期更新,只会在处理完成后更新。我已经尝试过使用SwingUtilities.invokeLater(),但不知怎的,事实证明处理任务是稍后完成的,所有完成的消息都是在处理执行之前先打印的,所以我正在尝试invokeAndWait()。
我一直在寻找答案,但大多数只是举例说明了JProgressBar,其中GUI和更新是在同一个类中完成的,而对于我的情况,2则是分开的。我也考虑过SwingWorker,但不知道我应该在哪里以及如何实现它,因为它会改变我的程序结构。
以下是我的代码。很抱歉它很乱,而且命名不是很连贯,我正在尝试很多东西来使进度条更新,并且需要一些时间来重新组织(但基本上代码工作正常)。
GUI类(具体参见方法getYesButton()):
public class TextureRevertPanel extends JPanel {
private TextureEditor te;
private TextureEditorGUI parent;
private JButton yesButton;
private JButton noButton;
private String imgtype;
private String path;
private JProgressBar pbar;
static final int MY_MINIMUM = 0;
static final int MY_MAXIMUM = 100;
public TextureRevertPanel(TextureEditor te, TextureEditorGUI parent, String imgtype, String path) {
super();
this.parent = parent;
setPreferredSize(new Dimension(800, 400));
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(5, 5, 5, 5);
c.anchor = GridBagConstraints.WEST;
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 2;
add(new JLabel("Energy saving mode is turned ON, do you want to turn it off?"), c);
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 2;
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
bottomPanel.add(getYesButton());
bottomPanel.add(getNoButton());
add(bottomPanel, c);
c.gridx = 0;
c.gridy = 4;
c.gridwidth = 1;
add(new JLabel("Progress"), c);
c.gridx = 1;
c.gridy = 4;
c.gridwidth = 1;
pbar = new JProgressBar();
pbar.setMinimum(MY_MINIMUM);
pbar.setMaximum(MY_MAXIMUM);
// add to JPanel
add(pbar, c);
this.te = te;
this.path = path;
this.imgtype = imgtype;
}
private JButton getYesButton() {
if (yesButton == null) {
yesButton = new JButton("Yes");
yesButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (MouseEvent.BUTTON1 == e.getButton()) {
boolean b = te.revertTextures("Y", path, imgtype, pbar);
if (b) {
/*JOptionPane.showMessageDialog(
parent.getMainFrame(),
"Textures in " + path + " have been reverted back",
"Notification", JOptionPane.INFORMATION_MESSAGE);*/
//parent.showMainPane();
}
}
}
});
}
return yesButton;
}
private JButton getNoButton() {
if (noButton == null) {
noButton = new JButton("No");
noButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (MouseEvent.BUTTON1 == e.getButton()) {
parent.showMainPane();
}
}
});
}
return noButton;
}
}
按Yes,该类将调用TextureEditor类的方法revertTextures()。 JProgressBar pbar作为参数传递给方法。
然后,TextureEditor中的revertTextures方法:
public boolean revertTextures(String input, String texturepath, String imgtype, JProgressBar pbar) {
System.out.println("Energy saving mode is on, do you want to turn it off?(Y/N)");
if (input.equalsIgnoreCase("Y")) {
System.out.println("Turning off energy saving mode...");
//copy all the png in the backup folder to texture folder
final String tpath = texturepath;
final String imagetype = imgtype;
this.pbar = pbar;
final Runnable doHelloWorld = new Runnable() {
public void run() {
System.out.println("Hello World on " + Thread.currentThread());
restorebackup(tpath, imagetype);
}
};
Thread appThread = new Thread() {
@Override
public void run() {
try {
SwingUtilities.invokeAndWait(doHelloWorld);
String text = "OFF";
try {
File file = new File(tpath + "backup\\indicator.txt");
BufferedWriter output = new BufferedWriter(new FileWriter(file));
output.write(text);
output.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Energy saving mode has been turned off.");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Finished on " + Thread.currentThread());
}
};
appThread.start();
然后在线程内部,调用实际处理方法restorebackup()。这是应该更新JProgressBar的地方:
public void restorebackup(String tpath, String imgtype) {
File backuppath = new File(tpath + "backup\\");
final File[] files = backuppath.listFiles();
final String imagetype = "." + imgtype;
final String texpath = tpath;
final String imagtype = imgtype;
for (int i = 0; i < files.length; i++) {
final int ii = i;
System.out.println(files[i].getName());
File texturepath;
BufferedImage image;
try {
System.out.println(files[ii]);
if (files[ii].getName().contains(imagetype)) {
texturepath = new File(texpath + files[ii].getName());
image = ImageIO.read(files[ii]);
ImageIO.write(image, imagtype, texturepath);
double proportion = (ii / (double) (files.length - 1)); //count out the indicator file
System.out.println((int) (proportion * 100) + "%");
pbar.setValue((int) (proportion * 100));
}
} catch (IOException e) {
System.out.println("Could not open texture files in backup folder");
}
}
System.out.println("Done");
}
答案 0 :(得分:0)
您没有从后台线程调用restorebackup()
。你是从事件调度线程调用它,因为它的调用被包含在对SwingUtilities.invokeAndWait()
的调用中。因此,此方法中的所有工作都在UI线程中完成,冻结它并阻止它更新UI直到方法完成。
您必须在后台线程中完成所有这项工作,但进度条的更新除外,该更新必须包含在SwingUtilities.invokeLater()
来电中。
或者更好的是,您应该阅读SwingWorker的文档并使用它。
答案 1 :(得分:0)
好的,最后我决定在TextureEditor类中使用SwingWorker类。这解决了我的问题。但是,我需要将restorebackup()操作复制到doInBackGround()。
private static class MySwingWorker extends SwingWorker<String, Double> {
private final JProgressBar fProgressBar;
private final String tpath;
private final String imagetype;
private final TextureEditorGUI parent;
private MySwingWorker(JProgressBar aProgressBar, String tpath, String imagetype, TextureEditorGUI parent) {
fProgressBar = aProgressBar;
this.tpath = tpath;
this.imagetype = imagetype;
this.parent = parent;
}
@Override
protected String doInBackground() throws Exception {
File backuppath = new File(tpath + "backup\\");
File texturepath;
final File[] files = backuppath.listFiles();
BufferedImage image;
final String texpath = tpath;
for (int i = 0; i < files.length; i++) {
final int ii = i;
try {
System.out.println(files[i].getName());
System.out.println(files[ii]);
if (files[ii].getName().contains("." + imagetype)) {
texturepath = new File(texpath + files[ii].getName());
image = ImageIO.read(files[ii]);
ImageIO.write(image, imagetype, texturepath);
double proportion = (ii / (double) (files.length - 1)); //count out the indicator file
publish(proportion);
System.out.println((int) (proportion * 100) + "%");
}
} catch (IOException e) {
System.out.println("Could not open texture files in backup folder");
}
}
return "Finished";
}
@Override
protected void process(List<Double> aDoubles) {
//update the percentage of the progress bar that is done
int amount = fProgressBar.getMaximum() - fProgressBar.getMinimum();
fProgressBar.setValue((int) (fProgressBar.getMinimum() + (amount * aDoubles.get(aDoubles.size() - 1))));
}
@Override
protected void done() {
try {
JOptionPane.showMessageDialog(
parent.getMainFrame(),
"Textures in " + tpath + " have been reverted back",
"Notification", JOptionPane.INFORMATION_MESSAGE);
parent.showMainPane();
} catch (Exception ignore) {
}
}
}
但是,我的TextureEditor类中还有另一个方法,它还需要进度条更新。这是否意味着我需要为其他方法创建另一个SwingWorker类,或者SwingWorker内部的条件化(即将参数传递给SwingWorker,它将通过条件执行不同方法的不同操作)?