java - jProgressBar 带有用于数据库数据插入的线程

标签 java multithreading swing progress-bar

我正在尝试实现一个 JprogressBar 来显示数据插入进度。 基本上,用户选择将多少数据源导入到数据库中。 使用此参数,主程序启动一个方法来列出这些参数,并使用 foreach 循环调用插入线程和 ProgressBar 更新线程。

for (Maquina i : m.listar()) {
    //Passing to Import Thread the object with the data and a Date parameter
    ImportarDados imp = new ImportarDados(i, jDateInicial.getDate());

    //Calling progress bar update Thread with the progressbar itself and progress parameter
    BarraDeProgresso bp = new BarraDeProgresso(progresso, progImportacao);

    imp.run();
    bp.run();
}

线程有点自己工作,但结果不是我想要的,因为正在导入数据并且正在更新进度条,但在导入所有数据后它正在更新到 100%。只要导入线程完成每个(Maquina i)对象的导入,我就需要更新进度条。

如果有必要我可以提供线程代码...但我不知道这个调用方法是否可以提供我想要的结果。在论坛上搜索时,我发现了一些有关 EDT 的信息,我认为问题在于该栏未更新。你们能帮我解决这个问题吗?

最小且可验证的示例: 我的代码很短。抱歉,netbeans 生成的代码非常庞大。

该代码模拟了我的问题。仅在 for 循环完成后才会刷新窗口。但是 BarraDeProgresso 线程与 SysOut 线程同时运行,并输出一些信息...

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JLabel;
import javax.swing.JProgressBar;



public class Minimo extends javax.swing.JFrame {


   public Minimo() {
       initComponents();
   }

   private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
       int progImportacao[] = {0};

       progresso.setMaximum(15);
       for (int i = 0; i <= 15; i++) {
           ImportarDados imp = new ImportarDados(i,lblProgresso);
           BarraDeProgresso bp = new BarraDeProgresso(progresso, progImportacao);

           imp.run();
           bp.run();

           progImportacao[0] += 1;
       }
   } 

组件初始化(Netbeans 生成)

private void initComponents() {

    progresso = new javax.swing.JProgressBar();
    lblProgresso = new javax.swing.JLabel();
    jButton1 = new javax.swing.JButton();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    lblProgresso.setText("...");

    jButton1.setText("IMPORT DATA");
    jButton1.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jButton1ActionPerformed(evt);
        }
    });

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addGap(60, 60, 60)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(lblProgresso)
                .addComponent(progresso, javax.swing.GroupLayout.PREFERRED_SIZE, 382, javax.swing.GroupLayout.PREFERRED_SIZE))
            .addContainerGap(47, Short.MAX_VALUE))
        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(jButton1)
            .addGap(191, 191, 191))
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addGap(32, 32, 32)
            .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 29, Short.MAX_VALUE)
            .addComponent(lblProgresso)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
            .addComponent(progresso, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addGap(37, 37, 37))
    );

    pack();
}// </editor-fold>

可运行类

class BarraDeProgresso implements Runnable {

    public JProgressBar jProgressBar1;
    public int progresso[];

    public BarraDeProgresso(JProgressBar barra, int progresso[]) {
        this.jProgressBar1 = barra;
        this.progresso = progresso;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(0);
            System.out.println("TBARRA PROG " + progresso[0]);
            jProgressBar1.setValue(progresso[0]);
            jProgressBar1.repaint();
        } catch (InterruptedException e) {
        }

    }
}

class ImportarDados implements Runnable {

    private int pi = 0;
    JLabel x;

    public ImportarDados(int i, JLabel tag) {
        this.pi = i;
        this.x = tag;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(500);

            x.setText(Integer.toString(pi)+" /15");

        } catch (InterruptedException ex) {
            Logger.getLogger(Minimo.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
} 

主要(Netbeans 生成)

public static void main(String args[]) {
    /* Set the Nimbus look and feel */
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
     * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
     */
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(Minimo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(Minimo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(Minimo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(Minimo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    //</editor-fold>

    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            new Minimo().setVisible(true);
        }
    });
}

最佳答案

您当前的代码没有创建后台线程。是的,您已经有了 Runnables,但是您对它们调用 run(),这意味着您在 Swing 事件线程上调用它们。当您这样做时,您会阻塞事件线程,从而有效地卡住您的程序。相反,您需要:

  • 通过将 Runnable 传递到 Thread 对象的构造函数并在该线程上调用 start() 来创建真正的后台线程。
  • 不会在这些后台线程中改变 Swing 组件
  • 或者按照 Lesson: Concurrency in Swing 使用 SwingWorker这将有助于解决上述两个问题。

有关 SwingWorker 的使用示例,请参阅:

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;

@SuppressWarnings("serial")
public class Minimo2 extends JPanel {
    private static final int EB_GAP = 15;
    private static final int PROG_BAR_WDTH = 400;
    public static final int MAX_DATA = 15;
    private JProgressBar progresso;
    private JLabel lblProgresso;
    private JButton jButton1;
    private Action importDataAction = new ImportDataAction("Import Data");

    public Minimo2() {
        initComponents();
    }

    private void initComponents() {
        progresso = new JProgressBar(0, MAX_DATA);
        lblProgresso = new JLabel(" ");
        jButton1 = new JButton(importDataAction);
        int progBarHeight = progresso.getPreferredSize().height;
        progresso.setPreferredSize(new Dimension(PROG_BAR_WDTH, progBarHeight));
        progresso.setStringPainted(true);

        JPanel btnPanel = new JPanel();
        btnPanel.add(jButton1);
        JPanel labelPanel = new JPanel();
        labelPanel.add(lblProgresso);
        JPanel progressPanel = new JPanel();
        progressPanel.add(progresso);

        setBorder(BorderFactory.createEmptyBorder(EB_GAP, EB_GAP, EB_GAP, EB_GAP));
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
        add(btnPanel);
        add(Box.createVerticalStrut(EB_GAP));
        add(labelPanel);
        add(Box.createVerticalStrut(EB_GAP));
        add(progressPanel);
    }

    private class ImportDataAction extends AbstractAction {
        public ImportDataAction(String name) {
            super(name); // give the button text
            int mnemonic = (int) name.charAt(0);
            putValue(MNEMONIC_KEY, mnemonic); // give it a hot key
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            setEnabled(false); // disable our button
            ImportDataWorker worker = new ImportDataWorker(MAX_DATA);
            worker.addPropertyChangeListener(new WorkerListener());
            worker.execute();
        }
    }

    private class WorkerListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
                int progValue = (int) evt.getNewValue();
                progresso.setValue(progValue);
                String text = String.format("%02d/15", progValue);
                lblProgresso.setText(text);
            } else if ("state".equals(evt.getPropertyName())) {
                if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
                    @SuppressWarnings("rawtypes")
                    SwingWorker worker = (SwingWorker)evt.getSource();
                    try {
                        worker.get();
                    } catch (InterruptedException | ExecutionException e) {
                        e.printStackTrace();
                    }
                    progresso.setValue(MAX_DATA);
                    String text = String.format("%02d/15", MAX_DATA);
                    lblProgresso.setText(text);
                    importDataAction.setEnabled(true);
                }
            }
        }
    }

    private class ImportDataWorker extends SwingWorker<Void, Void> {

        private static final long SLEEP_TIME = 500;
        private int max;

        public ImportDataWorker(int max) {
            this.max = max;
        }

        @Override
        protected Void doInBackground() throws Exception {
            for (int i = 0; i < max; i++) {                
                setProgress(i);
                Thread.sleep(SLEEP_TIME);
            }
            return null;
        }

    }

    private static void createAndShowGui() {
        Minimo2 mainPanel = new Minimo2();

        JFrame frame = new JFrame("Minimo2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

关于java - jProgressBar 带有用于数据库数据插入的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44830101/

相关文章:

java - "localhost"是 Java 中的常量吗?

multithreading - 为什么基于 channel 的 Lock block ?

java - JTable 中的 BeansBinding 和 JTable 的 TableColumn

Java 循环属性并使用反射修改默认值

java - 在 Java 中创建带有子节点的 SOAP 消息

java android studio - 检查权限

c++ - 如何安全终止多线程进程

java - 多个线程与管道流通信并使用 PushbackInputStream

java - 如何在 Java 中构建自定义 JTable,并在列名称上方添加一行

java - 二维字符串传递到 JTable