2

我有一个带有按钮的框架,当按下它时会JDialog显示一个带有进度条的框架,并且正在使用 jdbc 驱动程序获取一些数据(正在更新进度条)。我需要一个取消按钮,所以我花了一些时间弄清楚如何连接所有东西。它似乎有效,但我真诚地不确定这种方式是否有好处。如果有人有空闲时间,请检查此代码并告诉我它是否有任何问题 - 主要是整个 SwingWorker 和取消的东西。

在我的电脑(Linux)上,不成功的网络连接尝试(someNetworkDataFetching 方法)需要一整分钟才能超时,当我尝试创建新的时,我是否必须担心仍在工作的 SwingWorkers(尽管被取消但仍在等待连接)?

注意:您需要 mysql jdbc 驱动程序库来运行此代码。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class Test extends JFrame {

    private JProgressBar progressBar = new JProgressBar();
    private JLabel label = new JLabel();
    private DataFetcherProgress dfp;

    /**
     * This class holds retrieved data.
     */
    class ImportantData {

        ArrayList<String> chunks = new ArrayList<>();

        void addChunk(String chunk) {
            // Add this data 
            chunks.add(chunk);
        }
    }

    /**
     * This is the JDialog which shows data retrieval progress.
     */
    class DataFetcherProgress extends JDialog {

        JButton cancelButton = new JButton("Cancel");
        DataFetcher df;

        /**
         * Sets up data fetcher dialog.
         */
        public DataFetcherProgress(Test owner) {
            super(owner, true);
            getContentPane().add(progressBar, BorderLayout.CENTER);
            // This button  cancels the data fetching worker.
            cancelButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    df.cancel(true);

                }
            });
            getContentPane().add(cancelButton, BorderLayout.EAST);
            setLocationRelativeTo(owner);
            setSize(200, 50);
            df = new DataFetcher(this);
        }

        /**
         * This executes data fetching worker.
         */
        public void fetchData() {
            df.execute();
        }
    }

    class DataFetcher extends SwingWorker<ImportantData, Integer> {

        DataFetcherProgress progressDialog;

        public DataFetcher(DataFetcherProgress progressDialog) {
            this.progressDialog = progressDialog;
        }

        /**
         * Update the progress bar.
         */
        @Override
        protected void process(List<Integer> chunks) {
            if (chunks.size() > 0) {
                int step = chunks.get(chunks.size() - 1);
                progressBar.setValue(step);
            }
        }

        /**
         * Called when worker finishes (or is cancelled).
         */
        @Override
        protected void done() {
            System.out.println("done()");
            ImportantData data = null;
            try {
                data = get();
            } catch (InterruptedException | ExecutionException | CancellationException ex) {
                System.err.println("done() exception: " + ex);
            }
            label.setText(data != null ? "Retrieved data!" : "Did not retrieve data.");
            progressDialog.setVisible(false);
        }

        /**
         * This pretends to do some data fetching.
         */
        private String someNetworkDataFetching() throws SQLException {
            DriverManager.getConnection("jdbc:mysql://1.1.1.1/db", "user", "pass");
            // Retrieve data...
            return "data chunk";
        }

        /**
         * This tries to create ImportantData object.
         */
        @Override
        protected ImportantData doInBackground() throws Exception {
            // Show the progress bar dialog.
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    dfp.setVisible(true);
                }
            });

            ImportantData data = new ImportantData();
            try {
                int i = 0;
                // There is a network operation here (JDBC data retrieval)
                String chunk1 = someNetworkDataFetching();
                if (isCancelled()) {
                    System.out.println("DataFetcher cancelled.");
                    return null;
                }
                data.addChunk(chunk1);
                publish(++i);

                // And another jdbc data operation....
                String chunk2 = someNetworkDataFetching();
                if (isCancelled()) {
                    System.out.println("DataFetcher cancelled.");
                    return null;
                }
                data.addChunk(chunk2);
                publish(++i);
            } catch (Exception ex) {
                System.err.println("doInBackground() exception: " + ex);
                return null;
            }
            System.out.println("doInBackground() finished");
            return data;
        }
    }

    /**
     * Set up the main window.
     */
    public Test() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        label.setHorizontalAlignment(SwingConstants.CENTER);
        getContentPane().add(label, BorderLayout.CENTER);
        // Add a button starting data fetch.
        JButton retrieveButton = new JButton("Do it!");
        retrieveButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                fetchData();
            }
        });
        getContentPane().add(retrieveButton, BorderLayout.EAST);
        setSize(400, 75);
        setLocationRelativeTo(null);
        progressBar.setMaximum(2);
    }

    // Shows new JDialog with a JProgressBar and calls its fetchData()
    public void fetchData() {
        label.setText("Retrieving data...");
        dfp = new DataFetcherProgress(this);
        dfp.fetchData();
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    // Use jdbc mysql driver
                    Class.forName("com.mysql.jdbc.Driver");
                } catch (ClassNotFoundException ex) {
                    ex.printStackTrace();
                    return;
                }

                // Show the Frame
                new Test().setVisible(true);
            }
        });

    }
}
4

1 回答 1

4

关于我唯一可能做的不同的事情是不使用方法SwingUtilities.invokeLater中的doInBackground来显示对话框,但可能使用 aPropertyChangeListener来监视对state属性工作者的更改。

我还将使用PropertyChangeListener来监视progress工人财产的变化。而不是使用publish来指示进度变化,我会使用该setProgress方法(以及getProgressPropertyChangeListener

例如... java swingworker thread to update main Gui

我也可能会考虑在 a 上创建 UIJPanel并将其添加到JDialog而不是扩展目录中,JDialog因为如果您愿意,它会给以其他方式重用面板的机会...

于 2013-08-22T01:43:38.557 回答