4

当用户单击按钮时,将运行大约 10 秒的长任务。在此期间,我想向用户显示进度条。但是主线程必须等待工作线程完成,因为工作线程将设置一个主线程将使用的变量。如果我不等待工作线程,我会NullPointerException在使用变量时得到一个。所以在工作线程完成后,我也会关闭进度条对话框。

join()当我使用进度条对话框等待工作线程时(有趣的是没有进度条)并挂在那里。

Thread runnable = new Thread() {

    public void run() {
        try {
            System.out.println("thread basladi");
            threadAddSlaveReturnMessage = request.addSlave(
                ipField.getText(), passField.getText(), 
                nicknameField.getText());
            System.out.println("thread bitti");

        } catch (LMCTagNotFoundException e) {
            e.printStackTrace();
        }

    }
};

Thread runnable_progress = new Thread() {

    public void run() {

        JTextArea msgLabel;
        JDialog dialog;
        JProgressBar progressBar;
        final int MAXIMUM = 100;
        JPanel panel;

        progressBar = new JProgressBar(0, MAXIMUM);
        progressBar.setIndeterminate(true);
        msgLabel = new JTextArea("deneme");
        msgLabel.setEditable(false);


        panel = new JPanel(new BorderLayout(5, 5));
        panel.add(msgLabel, BorderLayout.PAGE_START);
        panel.add(progressBar, BorderLayout.CENTER);
        panel.setBorder(BorderFactory.createEmptyBorder(11, 11, 11, 11));

        dialog = new JDialog(Frame.getFrames()[0], "baslik", true);
        dialog.getContentPane().add(panel);
        dialog.setResizable(false);
        dialog.pack();
        dialog.setSize(500, dialog.getHeight());
        dialog.setLocationRelativeTo(null);
        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        dialog.setAlwaysOnTop(false);
        dialog.setVisible(true);
        msgLabel.setBackground(panel.getBackground());
    }
};

runnable.start();
System.out.println("runnable start");
runnable_progress.start();
System.out.println("progress start");
runnable.join();
System.out.println("runnable join");
runnable_progress.join();
System.out.println("progress join");


if (threadAddSlaveReturnMessage.equalsIgnoreCase("OK")) {
    fillInventoryTable(inventoryTable);
    JOptionPane.showMessageDialog(this, messages.getString("centrum.addslavepanel.SUCCESS"), null, JOptionPane.INFORMATION_MESSAGE);
}

“进度加入”

没有被打印出来。

4

3 回答 3

4

您可以在此处使用SwingWorker。一个简短的例子:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.godel.nio;

import java.awt.BorderLayout;
import java.util.List;
import javax.swing.*;

/**
 *
 * @author internet_2
 */
public class Test {

    public static void main(String[] args) {
        new Test().doJob();
    }

    public void doJob() {

        JTextArea msgLabel;
        JProgressBar progressBar;
        final int MAXIMUM = 100;
        JPanel panel;

        progressBar = new JProgressBar(0, MAXIMUM);
        progressBar.setIndeterminate(true);
        msgLabel = new JTextArea("deneme");
        msgLabel.setEditable(false);

        panel = new JPanel(new BorderLayout(5, 5));
        panel.add(msgLabel, BorderLayout.PAGE_START);
        panel.add(progressBar, BorderLayout.CENTER);
        panel.setBorder(BorderFactory.createEmptyBorder(11, 11, 11, 11));

        final JDialog dialog = new JDialog();
        dialog.getContentPane().add(panel);
        dialog.setResizable(false);
        dialog.pack();
        dialog.setSize(500, dialog.getHeight());
        dialog.setLocationRelativeTo(null);
        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        dialog.setAlwaysOnTop(false);
        dialog.setVisible(true);
        msgLabel.setBackground(panel.getBackground());

        SwingWorker worker = new SwingWorker() {

            @Override
            protected void done() {
                // Close the dialog
                dialog.dispose();
            }

            @Override
            protected void process(List chunks) {
                // Here you can process the result of "doInBackGround()"
                // Set a variable in the dialog or etc.
            }

            @Override
            protected Object doInBackground() throws Exception {
                // Do the long running task here
                // Call "publish()" to pass the data to "process()"
                // return something meaningful
                return null;
            }
        };

        worker.execute();

    }
}

编辑:应该在“doInBackground()”中调用“publish()”以将数据传递给“process()”

于 2012-08-24T08:10:51.390 回答
3
  1. 你有Concurency is Swing的问题,在所有线程完成后你的 GUI 是可见的

  2. 可以使用JProgressBar移动(我说的是你的代码),但你必须

    • 创建并显示JDialog,创建一次并重用此容器

    • 然后开始Thread

    • 更好的可能来自Runnable#Thread

    • Swing GUI 的输出必须包含在invokeLater()

  3. 这正是使用SwingWorkerPropertyChangeListener的工作

于 2012-08-24T08:06:03.020 回答
2

正如前面已经提到的答案SwingWorker,如果使用想要与 Swing 一起使用并发,这是要走的路。
我发现这个SwingWorker 和 ProgressBar 教程对于理解它们如何协同工作非常有用。

回到您的实际问题:我假设您使用 GUI,因为您声明用户必须单击一个按钮。问题是,你的“主线程”在做什么?它真的必须一直运行吗?看起来不像。因为您说线程需要一个由另一个线程设置的变量,这是用户交互的结果。简而言之:如果它依赖于用户交互,为什么它需要运行?
通常的方法是首先获取您需要的所有数据,然后运行计算或其他方式。在您的情况下,要么在单个后台线程中运行所有内容(首先设置变量然后执行其余部分),由按钮的 ActionListener 启动,或者在您设置变量的线程完成后运行另一个线程。
例如,您可以使用done()提供的方法SwingWorker来启动下一个任务。或者如果你真的需要,你可以在循环中等待task.isDone()返回true。但也不要忘记检查isCancelled()

无论如何,我认为你应该重新考虑你的设计。因为我从提供的有限信息中看到的对我来说过于复杂。

于 2012-08-24T09:05:21.433 回答