Chamar JDialog dentro de uma Thread

7 respostas
D

Pessoal

Estou tentando de várias maneiras fazer uma telinha que fique mostrando um JProgressBar enquanto o sistema se conecta ao banco de dados, mas estou encontrando algumas dificuldade ao chamar um JDialog que fiz com o bendito JProgressBar rodando.

Esse código está em um JFrame que faz a chamada ao JDialog e depois se conecta ao banco:

JDialogConectando aguarde = new JDialogConectando(this, "Aguarde...", "Conectando ao banco de dados...");

        aguarde.setVisible(true);
        try {
            PersistenciaServices.conectarAoBancoPrincipal();
        } catch (Exception ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ocorreu um erro ao se conectar com a base de dados:\n\n" + ex.toString());
            abrirFormularioCentralizado(new AlterarPersistencia(this, true));
        }
        aguarde.dispose();

Meu problema é o seguinte, eu preciso chamar o JDialog e o sistema não pode parar de rodar, pois o JDialog deve surgir e a conexão com o banco deve continuar.
Então inicialmente eu chamava e Exibia o JDialog dentro de uma Thread, funcionava em partes, pois o JDIalog aparece vazio, sem nada, conforme imagem abaixo:

Sendo assim eu pensei que o problema estava na Thread, então decidi tirar a Thread e mudar o tipo do JDialog e deixei ele “ModalityType.MODELESS” de maneira que ele não trava a aplicação quando é exibido, seu construtor ficou assim:

public JDialogConectando(java.awt.Frame parent, String titulo, String textoBarra) {
        super(parent, ModalityType.MODELESS);
        initComponents();
        if (!textoBarra.isEmpty()) {
            jProgressBar1.setString(textoBarra);
            jProgressBar1.setStringPainted(true);
        } else {
            jProgressBar1.setStringPainted(false);
        }
        jProgressBar1.setIndeterminate(true);
        setTitle(titulo);
        setLocationRelativeTo(null);
        setResizable(false);
        setAlwaysOnTop(true);
    }

E mesmo assim não adiantou, o resultado é o mesmo mostrado na imagem, ele abre o JDialog e não trava o sistema, porém o JDialog fica em branco.

Se eu rodar o JDialog com seu próprio método Main, ele abre normal com o ProgressBar:

public static void main(String args[]) {

        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                JDialogConectando dialog = new JDialogConectando(new javax.swing.JFrame(), "", "");
                dialog.addWindowListener(new java.awt.event.WindowAdapter() {

                    @Override
                    public void windowClosing(java.awt.event.WindowEvent e) {
                        System.exit(0);
                    }
                });
                dialog.setVisible(true);
            }
        });
    }

Alguem sabe como resolver este problema?

Obrigado
Douglas Junior

7 Respostas

F

Primeiro vc precisa entender a necessidade de existirem 2 threads: uma já esta fazendo a execucao do seu processamento normal (main), entao pra atualizar a janelinha de progresso vc precisa criar outra.

http://www.guj.com.br/java/48799-exemplo-de-jprogressbar

D

fabim:
Primeiro vc precisa entender a necessidade de existirem 2 threads: uma já esta fazendo a execucao do seu processamento normal (main), entao pra atualizar a janelinha de progresso vc precisa criar outra.

http://www.guj.com.br/java/48799-exemplo-de-jprogressbar

Meu problema não é o JProgressBar, meu problema é que o Swing não termina de montar os componentes do JDialog, qualquer cosia que eu colocar no JDialog junto com o ProgressBar não aparece.

Eu não tenho a necessidade de alimentar o JProgressBar pois ele está como “setIndeterminate(true)”

Obrigado
Douglas Junior

D

fabim:
Primeiro vc precisa entender a necessidade de existirem 2 threads: uma já esta fazendo a execucao do seu processamento normal (main), entao pra atualizar a janelinha de progresso vc precisa criar outra.

http://www.guj.com.br/java/48799-exemplo-de-jprogressbar

Seguir o exemplo do link que me passou e não adiantou, continua abrindo o JDialog sem nada dentro, olha como ficou:

ANTES:

JDialogConectando aguarde = new JDialogConectando(this, "Aguarde...", "Conectando ao banco de dados...");  
      
    aguarde.setVisible(true);  
    try {  
        PersistenciaServices.conectarAoBancoPrincipal();  
    } catch (Exception ex) {  
        ex.printStackTrace();  
        JOptionPane.showMessageDialog(this, "Ocorreu um erro ao se conectar com a base de dados:\n\n" + ex.toString());  
        abrirFormularioCentralizado(new AlterarPersistencia(this, true));  
    }  
    aguarde.dispose();

DEPOIS:

final JDialogConectando aguarde = new JDialogConectando(this, "Aguarde...", "Conectando ao banco de dados...");
        aguarde.setVisible(true);

        try {
            new SwingWorker() {

                @Override
                protected Object doInBackground() throws Exception {
                    try {
                        PersistenciaServices.conectarAoBancoPrincipal();
                    } catch (Exception ex) {
                        aguarde.dispose();
                        throw ex;
                    }
                    return null;
                }

                @Override
                protected void done() {
                    aguarde.dispose();
                }
            }.execute();
            while (PersistenciaServices.dao == null || !PersistenciaServices.dao.getEntityManager().isOpen()) {
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(null, "Ocorreu um erro ao se conectar com a base de dados:\n\n" + ex.toString());
            abrirFormularioCentralizado(new AlterarPersistencia(null, true));
        }
V

O que foi aquele while vazio maluco que apareceu ali?

Dica: Ao disparar a thread, desabilite os botões que não serão mais acessados. Na última linha da thread, chame um código para reabilita-los.

Mas não faça o método do botão “travar” esperando a thread. Isso travará toda a janela. A idéia de separar em threads é justamente não deixar o Swing ocupado.

Outra dica: Se um dia precisar esperar uma thread, use o método join(). Esperar com while fará seu processamento subir a 100%.

D

ViniGodoy:
O que foi aquele while vazio maluco que apareceu ali?

Dica: Ao disparar a thread, desabilite os botões que não serão mais acessados. Na última linha da thread, chame um código para reabilita-los.

Mas não faça o método do botão “travar” esperando a thread. Isso travará toda a janela. A idéia de separar em threads é justamente não deixar o Swing ocupado.

Outra dica: Se um dia precisar esperar uma thread, use o método join(). Esperar com while fará seu processamento subir a 100%.

Obrigado pela resposta ViniGodoy

Aquele “while” existe para que não saia deste método enquanto não se conectar ao banco, pois são os métodos de inicialização do sistema, e depois desse vem o método de que chama o Login do usuário.

Funciona assim:

Quando o sistema inicia, abre o JFrame principal de no evento “windowOpened” eu chamos os métodos de conectarAoBaco, efetuarLogin, etc etc etc

Acontece que o JFrame fica parado até que se conecte ao banco, ainda mais quando se conecta a um banco via Internet, eu gostaria de deixar alguma coisa na tela para que o usuário percebesse que está se conectando ao banco, mas o sistema nao pode continuar enquanto não se conectar ao banco.

O exemplo que o fabim passou não é o JDialog com o JProgressBar que fica na Thread, e sim o método de conectar ao banco, então tive que colocar o While para ele continuar somente quando estivesse conectado ao banco de dados.

Mas aí vem a minha grande dúvida: Porque o JDialog abre em branco sendo que tudo o necessário para ele renderizar e aparecer acontece antes do método de conectar ao banco, ou seja, ele deveria aparecer por completo para somente depois chamar o método de conectar ao banco?

Obrigado
Douglas Junior

V

A tela fica em branco pq a thread do Swing, que faz o desenho, está travada.

Você deve imaginar o swing como um while, assim:

while (true) { processaEventos(); repintaTela(); }

Como seu código “travou” num evento de botão, o while do Swing nunca saiu do “processaEventos()” e, consequentemente, não repintou a tela.
Por isso, dizemos que o correto é mover processamentos pesados para outra thread, enquanto esse while fica livre.

Veja a dica que dei. Ao invés de você “travar” no botão, faça apenas o botão desabilitar as ações que o usuário poderá fazer em sua tela, mas deixe o código fluir.
Ao final do código da thread separada, no método done() do SwingWorker, coloque o código para reabilitar as ações. Isso deixará a thread do Swing livre para fazer a pintura, e te dará uma interface responsiva.

D

ViniGodoy:
A tela fica em branco pq a thread do Swing, que faz o desenho, está travada.

Você deve imaginar o swing como um while, assim:

while (true) { processaEventos(); repintaTela(); }

Como seu código “travou” num evento de botão, o while do Swing nunca saiu do “processaEventos()” e, consequentemente, não repintou a tela.
Por isso, dizemos que o correto é mover processamentos pesados para outra thread, enquanto esse while fica livre.

Veja a dica que dei. Ao invés de você “travar” no botão, faça apenas o botão desabilitar as ações que o usuário poderá fazer em sua tela, mas deixe o código fluir.
Ao final do código da thread separada, no método done() do SwingWorker, coloque o código para reabilitar as ações. Isso deixará a thread do Swing livre para fazer a pintura, e te dará uma interface responsiva.

Muito obrigado ViniGodoy

Com sua última explicação consegui entender o problema, não se acha muito disso por aí, espero que este tópico seja útil para mais alguém.

Meu método de conexão ao banco ficou assim:

private void conectarAoBancoDeDados() {
        final JDialogConectando aguarde = new JDialogConectando(this, "Aguarde...", "Conectando ao banco de dados...");
        aguarde.setVisible(true);

        try {
            new SwingWorker() {

                @Override
                protected Object doInBackground() throws Exception {
                    try {
                        PersistenciaServices.conectarAoBancoPrincipal();
                    } catch (Exception ex) {
                        aguarde.dispose();
                        throw ex;
                    }
                    return null;
                }

                @Override
                protected void done() {
                    aguarde.dispose();
                    exibirStatusDeConexao();
                    autenticarLoginDeUsuario();
                }
            }.execute();
        } catch (Exception ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(null, "Ocorreu um erro ao se conectar com a base de dados:\n\n" + ex.toString());
            abrirFormularioCentralizado(new AlterarPersistencia(null, true));
        }
    }

Obrigado
Douglas Junior

Criado 5 de dezembro de 2011
Ultima resposta 6 de dez. de 2011
Respostas 7
Participantes 3