Java SwingWorker 与 JDialog 在 JDBC 网络操作期间显示 JProgressBar

标签 java swing jdbc swingworker

我有一个带有按钮的框架,按下按钮时会显示带有进度条的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);
            }
        });

    }
}

最佳答案

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

我还会使用 PropertyChangeListener 来监视工作线程的 progress 属性的更改。我不会使用 publish 来指示进度更改,而是使用 setProgress 方法(以及 PropertyChangeListener 中的 getProgress)

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

我还可能考虑在 JPanel 上创建 UI 并将其添加到 JDialog 中,而不是从 JDialog 扩展目录,因为它会给出如果您愿意,有机会以其他方式重新使用面板...

关于Java SwingWorker 与 JDialog 在 JDBC 网络操作期间显示 JProgressBar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18370267/

相关文章:

java - 如何在 BorderLayout 的中心使用 JScrollpane

spring - Mysql-Connector-Java 与 Spring-Jdbc 之间的区别

mysql - JDBC锁: how to tell an exception is caused by lock timeout?

java - 索引 2 超出范围

java - 段落条件嵌套正则表达式(递归)

java - 应用程序引擎中的代码分割

java - 使用 Eclipse 处理非英文字符

java - 如何偏移 JSilder 上的指针?

multithreading - JavaFX 的 Swing 计时器替代方案和线程管理差异

java - 如何消除动画过程中出现的闪烁?