0

编辑:注意,这个问题与我在这里的另一个问题有关:SwingWorker - Passing parameters and return an ArrayList<Object>

在挖掘了 SwingWorker 之后,为了尝试解决这个问题,我想出了这个 SSCCE 代码。

笔记结束

编辑结束

给定以下 SSCCE 代码:

import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class MainFrame extends JFrame {

    private JLabel countLabel1 = new JLabel("0");
    private JLabel statusLabel1 = new JLabel("Task not completed.");
    private JLabel statusLabel2 = new JLabel("Task not completed.");
    private JLabel statusLabel3 = new JLabel("Task not completed.");
    private JButton startButton = new JButton("Start");
    private ArrayList<Train> trainList = new ArrayList<>();
    private ArrayList<Train> processedTrains = new ArrayList<>();

    public MainFrame(String title) {
        super(title);

        setLayout(new GridBagLayout());

        countLabel1.setFont(new Font("serif", Font.BOLD, 28));

        GridBagConstraints gc = new GridBagConstraints();

        gc.fill = GridBagConstraints.NONE;

        gc.gridx = 0;
        gc.gridy = 0;
        gc.weightx = 1;
        gc.weighty = 1;
        add(countLabel1, gc);

        gc.gridx = 0;
        gc.gridy = 1;
        gc.weightx = 1;
        gc.weighty = 1;
        add(statusLabel1, gc);

        gc.gridx = 0;
        gc.gridy = 2;
        gc.weightx = 1;
        gc.weighty = 1;
        add(statusLabel2, gc);

        gc.gridx = 0;
        gc.gridy = 3;
        gc.weightx = 1;
        gc.weighty = 1;
        add(statusLabel3, gc);

        gc.gridx = 0;
        gc.gridy = 4;
        gc.weightx = 1;
        gc.weighty = 1;
        add(startButton, gc);

        Train t1 = new Train();
        t1.setId(1);
        t1.setName("John");

        Train t2 = new Train();
        t2.setId(2);
        t2.setName("Mark");

        Train t3 = new Train();
        t3.setId(3);
        t3.setName("Lewis");


        trainList.add(t1);
        trainList.add(t2);
        trainList.add(t3);


        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                TrainMethods tm = new TrainMethods();

                // How can the swing worker return the array from the
                // processTrains method to this processedTrains array
                processedTrains = tm.processTrains(trainList);

                for (int i = 0; i < processedTrains.size(); i++) {
                    System.out.println("Train id: " + processedTrains.get(i).getId()
                            + " Train Name: " + processedTrains.get(i).getName());
                }
            }
        });

        setSize(200, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
// Notice that it kicks it off on the event-dispatching thread, not the main thread.
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                MainFrame mf = new MainFrame("Yo");
            }
        });
    }

    private class Train {
        String name;
        int id;

        public void setName(String name) {
            this.name = name;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public int getId() {
            return id;
        }
    }

    private class TrainMethods {

        public ArrayList processTrains(final ArrayList<Train> trainList) {
            // Add here a SwingWorker to create a new thread
            // and execute the following code and update later on
            // a progress bar
            SwingWorker<ArrayList, Integer> worker = new SwingWorker<ArrayList, Integer>() {
                @Override
                protected ArrayList doInBackground() throws Exception {
                    for(int i = 0; i<trainList.size(); i++)
                    {
                        trainList.get(i).setName("No name");
                        publish(i);
                    }
                return trainList;
                }

                @Override
                protected void process(List<Integer> chunks) {
                    int mostRecentValue = chunks.get(chunks.size() - 1);
                    countLabel1.setText(Integer.toString(mostRecentValue));
                }

                @Override
                protected void done() {
                    ArrayList<Train> status;
                    try {
                        // Retrieve the return value of doInBackground.
                        status = get();
                        statusLabel1.setText("Completed Train 1 with name: " + status.get(0).getName());
                        statusLabel2.setText("\nCompleted Train 2 with name: " + status.get(1).getName());
                        statusLabel3.setText("\nCompleted Train 3 with name: " + status.get(2).getName());
                    } catch (InterruptedException | ExecutionException ex) {
                        Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            };
            worker.execute();

            return trainList;

//            for (int i = 0; i < trainList.size(); i++) {
//                trainList.get(i).setName("No name");
//            }
//            return trainList;
        }
    }
}

为什么要System.Out.Println()打印:

Train id: 1 Train Name: John
Train id: 2 Train Name: Mark
Train id: 3 Train Name: Lewis

用户界面打印时:No Name? 就我个人而言,我希望No Name在两者上都被打印出来。

问题1:为什么不同的输出?

问题 2:如何让它No Name在两个地方(Sysout 和 GUI)都输出?

_________________________ 编辑 _______________________________

问题3:为什么我第二次按下开始按钮时都会打印No Name

4

1 回答 1

3

doInBackground()不出所料,在后台运行。也就是说,它在另一个线程中执行。因此,您不能依赖该代码的执行顺序以及您的打印代码。因此,trainsList可以在打印之前、之后或期间修改 的内容。如果您确实需要立即获得结果,则需要添加一些同步(通常您不需要。这就是在另一个线程中运行任务以避免等待它完成的全部意义)。

最有可能正确的解决方案是根本没有打印代码,并让它按照SwingWorker预期的方式工作。结果以线程安全的方式提供done()(以及在process()子任务准备好后您需要的任何东西)。

在第二次运行中,您会得到“无名称”,因为您从未将名称重置为其他任何名称,因此它们是在上一次运行中设置的名称。

于 2013-10-23T18:09:29.683 回答