取消javax.swing框架

时间:2016-07-05 11:12:06

标签: java multithreading swing terminate

我有一个带有java.swing组件,ActionListeners和SwingWorker的GUI,可以在一个单独的线程中执行更多代码。据我所知,SwingWorker只能创建一次,不能终止,而是取消。此外,我认为使用其方法isCancelled()检查SwingWorker状态是好的做法,以防止退出doInBackground()方法并相应地对done()方法做出反应。如果您在doInBackground()方法中有一个循环,并且可以在每次迭代时测试isCancelled(),那么这很好。

但是如何真正打破/终止在doInBackground()方法中执行的长任务,例如读取大型csv(> 1GB)或从另一个类调用进程密集型方法?为了说明我的问题,我构建了一个简单的程序,当您选择一个大输入csv时,它会显示我的问题。停止按钮与计数器循环一起正常工作但不终止csv导入。

我怎样才能真正打破/终止一个持久的过程?如果使用SwingWorker无法做到这一点,我将如何使用线程执行此操作? thread.interrupt()是否可能?我将如何在我的示例中实现它?

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import com.opencsv.CSVReader;

public class MinimalSwing extends JFrame {
// fields
private JButton fileButton, startButton, stopButton;
private JLabel displayLabel;
private File csvIn;
private SwingWorkerClass swingWorker;

// constructor
public MinimalSwing() {
    // set GUI-window properties
    setSize(300, 200);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocation(200, 200);
    setTitle("MinimalSwing");
    setLayout(new BorderLayout(9, 9));
    setResizable(false);

    // set components
    fileButton = new JButton("Choose File");
    fileButton.addActionListener(new ButtonActionListener());
    getContentPane().add("North", fileButton);
    startButton = new JButton("Start");
    startButton.setEnabled(false);
    startButton.addActionListener(new ButtonActionListener());
    getContentPane().add("West", startButton);
    stopButton = new JButton("Stop");
    stopButton.setEnabled(false);
    stopButton.addActionListener(new ButtonActionListener());
    getContentPane().add("East", stopButton);
    displayLabel = new JLabel("Status...");
    getContentPane().add("South", displayLabel);
}

// csvFileChooser for import
private File getCsv() {
    JFileChooser fc = new JFileChooser();
    int openDialogReturnVal = fc.showOpenDialog(null);
    if(openDialogReturnVal != JFileChooser.APPROVE_OPTION){
        System.out.println("ERROR: Invalid file choice.");
    }
    return fc.getSelectedFile();
}

// csvImporter
private class CsvImporter {
    public void readCsv(File file) throws IOException {
        CSVReader reader = new CSVReader(new FileReader(file));
        String [] nextLine;
        reader.readNext();  
        while ((nextLine = reader.readNext()) != null) {    
            displayLabel.setText("..still reading");
        }
        reader.close();
        displayLabel.setText("..actually done.");
    }
}

// ActionListener
private class ButtonActionListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == fileButton) {
            csvIn = getCsv();
            if(csvIn != null) {
                startButton.setEnabled(true);
                stopButton.setEnabled(true);
            }
        }
        else if(e.getSource() == startButton) {
            fileButton.setEnabled(false);
            startButton.setEnabled(false);
            stopButton.setEnabled(true);
            swingWorker = new SwingWorkerClass();
            swingWorker.execute();
        }
        else {
            fileButton.setEnabled(true);
            startButton.setEnabled(true);
            stopButton.setEnabled(false);
            swingWorker.cancel(true);
        }
    }
}

// swingWorker to interact with further program
private class SwingWorkerClass extends SwingWorker<Boolean, Void> {
    @Override
    protected Boolean doInBackground() throws Exception {
        long t0 = System.currentTimeMillis();
        displayLabel.setText("starting execution...");
        displayLabel.setText("..importing csv");
        CsvImporter csvImporter = new CsvImporter();
        csvImporter.readCsv(csvIn);
        if(isCancelled()) return false; // this cancels after the import, but I want to cancel during the import...
        long t1 = System.currentTimeMillis();
        displayLabel.setText("csv imported in " + String.format("%,d", t1 - t0) + " ms");
        for(short i=1; i<=10; i++) {
            if(isCancelled()) return false; // this works fine as it is called every second
            TimeUnit.SECONDS.sleep(1);
            displayLabel.setText("counter: " + i);
        }
        return true;
    }

    @Override
    public void done() {
        fileButton.setEnabled(true);
        startButton.setEnabled(true);
        stopButton.setEnabled(false);
        if(isCancelled()) {
            displayLabel.setText("Execution cancelled.");
        }
        else {
            displayLabel.setText("Execution succeeded.");
        }
    }
}

// main
public static void main(String[] args) throws URISyntaxException, IOException {
    // launch gui
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            try {
                MinimalSwing frame = new MinimalSwing();
                frame.setVisible(true);
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

}

1 个答案:

答案 0 :(得分:1)

您可以使CSVImporter扩展SwingWorker,而不是再使用一个类SwingWorkerClass。通过这种方式,您可以获得更多控制权并取消导入任务。

如下所示。

  private class CsvImporter extends SwingWorker<Boolean, Void> {

        public boolean readCsv(File file) throws IOException {
            CSVReader reader = new CSVReader(new FileReader(file));
            String[] nextLine;
            reader.readNext();
            while ((nextLine = reader.readNext()) != null) {
                displayLabel.setText("..still reading");
                if (isCancelled())
                    return false; // this cancels after the import, but I want
                                    // to cancel during the import...
            }
            reader.close();
            displayLabel.setText("..actually done.");
            return true; // read complete
        }

        @Override
        protected Boolean doInBackground() throws Exception {
            long t0 = System.currentTimeMillis();
            displayLabel.setText("starting execution...");
            displayLabel.setText("..importing csv");
            CsvImporter csvImporter = new CsvImporter();
            boolean readStatus = csvImporter.readCsv(csvIn);
            if (readStatus) {
                long t1 = System.currentTimeMillis();
                displayLabel.setText("csv imported in " + String.format("%,d", t1 - t0) + " ms");
                for (short i = 1; i <= 10; i++) {
                    if (isCancelled())
                        return false; // this works fine as it is called every second
                    TimeUnit.SECONDS.sleep(1);
                    displayLabel.setText("counter: " + i);
                }
            }
            return readStatus;
        }
    }