Problema com Swing e Thread

Bom dia,

Estou tentando criar uma aplicação de importação de dados com Thread para que se possa tanto acompanhar a importação quanto poder pará-la e retomá-la.
Infelizmente mesmo usando threads a janela congela.
Já li várias soluções no fórum, mas nenhuma me permitindo o controle da thread gerada:

    private void btnImportarActionPerformed(java.awt.event.ActionEvent evt) {                                            

        if( !this.txtLinha.getText().equals( "0" ) )
        {
            int resposta = JOptionPane.CLOSED_OPTION;

            while( resposta != JOptionPane.CLOSED_OPTION )
            {
                resposta = JOptionPane.showConfirmDialog(this, "Deseja retomar de onde havia parado?", "Erro",  JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE );

                if (resposta == JOptionPane.NO_OPTION)
                    this.txtLinha.setText("0");
            }
        }

        if( this.txtLinha.getText().equals("0") && chkCabecalho.isSelected() )
            this.txtLinha.setText("1");

        if( txtArquivo.getText().length() == 0 )
            JOptionPane.showMessageDialog(this, "Favor selecionar um arquivo!", "Erro", JOptionPane.WARNING_MESSAGE);
        else if( txtDatabase.getText().length() == 0 )
            JOptionPane.showMessageDialog(this, "Favor selecionar um banco de dados!", "Erro", JOptionPane.WARNING_MESSAGE);
        else if( txtCep.getText().length() == 0 )
            JOptionPane.showMessageDialog(this, "Favor selecionar um banco de dados!", "Erro", JOptionPane.WARNING_MESSAGE);
        else if( this.cmbTipoBase.getSelectedIndex() == 0 )
            JOptionPane.showMessageDialog(this, "Favor selecionar um tipo de banco!", "Erro", JOptionPane.WARNING_MESSAGE);
        else
        {
            try
            {
                if( this.tb == null )
                    this.tb = ( TipoBase ) Class.forName( pckgname + '.' + this.cmbTipoBase.getSelectedItem().toString()).newInstance();

                if( ( this.thread != null ) && this.thread.isAlive() )
                {
                    int resposta = JOptionPane.CLOSED_OPTION;

                    while( resposta != JOptionPane.CLOSED_OPTION )
                    {
                        resposta = JOptionPane.showConfirmDialog(this, "Já existe uma importação em andamento. Parar e começar uma nova?", "Erro",  JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE );

                        if (resposta == JOptionPane.YES_OPTION)
                        {
                            this.txtLinha.setText("0");
                            this.txtLog.setText("");

                            this.thread.destroy();
                        }
                        else if (resposta == JOptionPane.NO_OPTION)
                            return;
                    }
                }
                else
                    this.txtLog.setText("");

                this.tb.configurar(this.txtArquivo.getText(), this.txtDatabase.getText(), new Integer( this.txtLinha.getText() ), this.txtCep.getText() );

                this.txtLog.setText( this.txtLog.getText() + "Rodando pré-importação...\n" );
                if( !this.tb.preImportar() )
                {
                    this.txtLog.setText( this.txtLog.getText() + "Erro na pré-importação!...\n" );
                    return;
                }

                if( this.chkLimpar.isSelected() )
                {
                    this.txtLog.setText( this.txtLog.getText() + "Limpando o banco de dados...\n" );
                    this.tb.limpar( stm );
                }

                this.txtLog.setText( this.txtLog.getText() + "Rodando importação...\n" );

                if( this.thread == null )
                    this.thread = new Thread( this.tb );

                this.thread.start();

                this.btnParar.setEnabled(true);

                this.txtLinha.setEditable(false);

                while( this.thread.isAlive() && !this.thread.isInterrupted() )
                {
                    this.txtLinha.setText( new Integer( tb.getContador() ).toString() );
                    this.txtLog.setText( this.txtLog.getText() + tb.getLog() );

                    Thread.sleep(1000);
                }

                this.txtLinha.setText( new Integer( tb.getContador() ).toString() );
                this.txtLog.setText( this.txtLog.getText() + tb.getLog() );

                this.btnParar.setText("Parar");
                this.btnParar.setEnabled(false);

                this.txtLinha.setEditable(true);

                if( this.tb.getStatus() )
                {
                    this.txtLog.setText( this.txtLog.getText() + "Importação finalizada com sucesso!" );
                    JOptionPane.showMessageDialog(this, "Importação finalizada com sucesso!", "Aviso", JOptionPane.DEFAULT_OPTION);
                }
                else
                {
                    this.txtLog.setText( this.txtLog.getText() + "Importação finalizada com problemas!" );
                    JOptionPane.showMessageDialog(this, "Importação finalizada com problemas!", "Erro", JOptionPane.ERROR_MESSAGE);
                }
            }
            catch( Exception e )
            {
                this.txtLog.setText(this.txtLog.getText() + "\n" + e.getMessage());
                e.printStackTrace();
            }
        }
    }                                           

Aqui http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html
Bom divertimento! :wink:

A questão não é Threads. A questão é: como você fará para controlar a importação (isto é: com base no que você saberá como retomar a importação). Creio que esse seja o maior problema (talvez controlar pelo número de linhas, ou pelo número de bytes lidos…).

Uma vez definido isso, implemente um SwingWorker e divirta-se.

Tentei por o SwingUtilities.invokeLater(this.thread); no lugar de this.thread.start();
O problema é que este nunca executa o meu código e o SwingUtilities.invokeAndWait(this.thread); não pode ser chamado de um tratamento de evento.

Primeiro: você já tem definido exatamente o procedimento para poder retomar a importação? Qual é esse procedimento?

    private void btnPararActionPerformed(java.awt.event.ActionEvent evt) {                                         

        try
        {
            if( this.thread.isInterrupted() )
            {
                this.thread.wait();
                this.btnParar.setText("Continuar");
            }
            else
            {
                this.thread.notifyAll();
                this.btnParar.setText("Parar");
            }
        }
        catch( Exception e )
        {
            this.txtLog.setText( this.txtLog.getText() + "A execução não pode ser parada!" );
            JOptionPane.showMessageDialog(this, "A execução não pode ser parada!", "Erro", JOptionPane.ERROR_MESSAGE);

            e.printStackTrace();
        }
    }

[quote=fabiofalci]Aqui http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html
Bom divertimento! :wink: [/quote]
Antes de concorrência em swing, sugiro estudar somente concorrência: http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html

Depois veja esse link que o Fábio passou.

Se houver alguma dúvida específica poderemos ajudar. Se não houver dúvida o máximo que podemos fazer é recomendar leituras sobre o assunto.

Na verdade, se tivesse como alguém dizer como devo startar a thread para poder pará-la e restartá-la…

Chegaste a ler o material que te passamos?

Raramente vc precisa criar um thread em swing, mas sim utilizá-las como o texto diz.
No teu caso acho q vc deve usar as Worker threads

Aqui o link direto http://java.sun.com/docs/books/tutorial/uiswing/concurrency/simple.html
Vc tentou usar um SwingWorker?

O SwingWorker permite parar e retomar processos?

Faça o seguinte: crie uma classe encarregada de fazer as importações. Ela ficará em um loop que será executado enquanto houver mais coisas a importar.

No final de cada iteração, verifique se o processo foi pausado (use um boolean para controlar isso, com o seu respectivo setter). Se foi, invoque o método wait() para bloquear a execução da Thread.

Quando o usuário pressionar continuar, chame um notifyAll para continuar a tarefa.

Leia atentamente essa referência e tome como base o exemplo: http://java.sun.com/docs/books/tutorial/essential/concurrency/guardmeth.html

Mudei o método para utilizar SwingUtilities e um timer para atualizar a página e continua congelando…


private void btnImportarActionPerformed(java.awt.event.ActionEvent evt) {                                            

        if( ( timer != null ) && timer.isRunning() )
            timer.stop();

        if( !this.txtLinha.getText().equals( "0" ) )
        {
            int resposta = JOptionPane.CLOSED_OPTION;

            while( resposta != JOptionPane.CLOSED_OPTION )
            {
                resposta = JOptionPane.showConfirmDialog(this, "Deseja retomar de onde havia parado?", "Erro",  JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE );

                if (resposta == JOptionPane.NO_OPTION)
                    this.txtLinha.setText("0");
            }
        }

        if( this.txtLinha.getText().equals("0") && this.chkCabecalho.isSelected() )
            this.txtLinha.setText("1");

        if( txtArquivo.getText().length() == 0 )
            JOptionPane.showMessageDialog(this, "Favor selecionar um arquivo!", "Erro", JOptionPane.WARNING_MESSAGE);
        else if( txtDatabase.getText().length() == 0 )
            JOptionPane.showMessageDialog(this, "Favor selecionar um banco de dados!", "Erro", JOptionPane.WARNING_MESSAGE);
        else if( txtCep.getText().length() == 0 )
            JOptionPane.showMessageDialog(this, "Favor selecionar um banco de dados!", "Erro", JOptionPane.WARNING_MESSAGE);
        else if( this.cmbTipoBase.getSelectedIndex() == 0 )
            JOptionPane.showMessageDialog(this, "Favor selecionar um tipo de banco!", "Erro", JOptionPane.WARNING_MESSAGE);
        else
        {
            try
            {
                if( this.tb == null )
                {
                    int resposta = JOptionPane.CLOSED_OPTION;

                    while( resposta != JOptionPane.CLOSED_OPTION )
                    {
                        resposta = JOptionPane.showConfirmDialog(this, "Já existe uma importação em andamento. Parar e começar uma nova?", "Erro",  JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE );

                        if (resposta == JOptionPane.YES_OPTION)
                        {
                            this.txtLinha.setText("0");
                            this.txtLog.setText("");

                            this.tb = null;
                        }
                        else if (resposta == JOptionPane.NO_OPTION)
                            return;
                    }
                }
                else
                    this.txtLog.setText("");

                this.tb = ( TipoBase ) Class.forName( pckgname + '.' + this.cmbTipoBase.getSelectedItem().toString()).newInstance();

                this.tb.configurar(this.txtArquivo.getText(), this.txtDatabase.getText(), new Integer( this.txtLinha.getText() ), this.txtCep.getText() );

                this.txtLog.setText( this.txtLog.getText() + "Rodando pré-importação...\n" );
                if( !this.tb.preImportar() )
                {
                    this.txtLog.setText( this.txtLog.getText() + "Erro na pré-importação!...\n" );
                    return;
                }

                if( this.chkLimpar.isSelected() )
                {
                    this.txtLog.setText( this.txtLog.getText() + "Limpando o banco de dados...\n" );
                    this.tb.limpar( stm );
                }

                this.txtLog.setText( this.txtLog.getText() + "Rodando importação...\n" );

                //this.thread.start();

                this.btnParar.setEnabled(true);
                this.txtLinha.setEditable(false);

                int delay = 100; //milliseconds
                ActionListener taskPerformer = new ActionListener() {
                    public void actionPerformed(ActionEvent evt) {

                        repaint();

                        if( tb.getStatus() == null )
                        {
                            txtLinha.setText( new Integer( tb.getContador() ).toString() );
                            txtLog.setText( txtLog.getText() + tb.getLog() );
                        }
                        else
                        {
                            btnParar.setText("Parar");
                            btnParar.setEnabled(false);

                            txtLinha.setText( new Integer( tb.getContador() ).toString() );

                            txtLinha.setEditable(true);

                            if( tb.getStatus() )
                            {
                                txtLog.setText( txtLog.getText() + "Importação finalizada com sucesso!" );
                                JOptionPane.showMessageDialog(null, "Importação finalizada com sucesso!", "Aviso", JOptionPane.DEFAULT_OPTION);
                            }
                            else
                            {
                                txtLog.setText( txtLog.getText() + "Importação finalizada com problemas!" );
                                JOptionPane.showMessageDialog(null, "Importação finalizada com problemas!", "Erro", JOptionPane.ERROR_MESSAGE);
                            }
                            
                            timer.stop();
                        }
                    }
                };

                timer = new Timer(delay, taskPerformer);

                SwingUtilities.invokeLater(this.tb);
                SwingUtilities.invokeLater( new Runnable(){
                    public void run(){
                        timer.start();
                    }
                });
            }
            catch( Exception e )
            {
                this.txtLog.setText(this.txtLog.getText() + "\n" + e.getMessage());
                e.printStackTrace();
            }
        }
    }