JProgressBar作为参数传递给其他类中的方法&不会更新?

时间:2013-12-14 14:16:25

标签: java swing jprogressbar

基本上,我有两个类: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");
}

2 个答案:

答案 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,它将通过条件执行不同方法的不同操作)?