Load com threads

39 respostas
R

Quero abrir uma tela com um gif enquanto minhas consultas estão rodando. Porém minha tela não aparece, mesmo sendo seu isVisible = true.
Minha aplicação é em Java desktop.

  • Código da thread:

import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;

public class ThreadLoad extends Thread {

        TelaLoad frame;
        private volatile boolean fecharFrame = true;

        @Override
        public void run() {
            try {
                if (!fecharFrame()) {
                    frame.setVisible(true);
                }
                frame.setVisible(false);
                frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);

            } catch (Exception e) {
                System.out.println("Erro thread: " + e.getMessage());
            }
        }

        public synchronized void requestStop() {
            this.fecharFrame = true;
        }

        public synchronized void requestStar() {
            fecharFrame = false;
        }

        public void frame(TelaLoad j) {
            frame = j;
        }

        public synchronized boolean fecharFrame() {
            return fecharFrame;
        }
    }
  • Utilizo um JDialog onde tenho as funções que utilizo:

    public void iniciar() {
              //se não tiver thread, abrir uma 
              if (t.fecharFrame()) {
                  t = new ThreadLoad();
                  t.frame(this);
                  t.requestStar();
                  t.start();
              }
          }
    
          public void fechar() {
              //se tiver thread, fecha-la
              if (!t.fecharFrame()) {
                  t.frame(this);
                  t.requestStop();
                  t.interrupt();
                  this.dispose();
              }
          }
    

Para abrir o load então uso tela.iniciar() e para chega tela.fechar(); Porém mesmo com requisições que demoram a tela com o gif não fica visível.
Alguém poderia me ajudar, obrigado.

39 Respostas

darlan_machado

Mas você já viu isso funcionando?

R

Vi exemplos na internet com load que utilizam tempos pré-definidos, porém eu não sei quanto tempo minha consulta dura. Logo, estou tentando fazer algo sem esse tempo, de modo a abrir e fechar um jdialog com a thread

staroski

Provavelmente pelo fato de você fechar ela, veja:

if (!fecharFrame()) {
        frame.setVisible(true); // abre
    }
    frame.setVisible(false);    // em seguida fecha
darlan_machado

Não exemplos na internet, fera. Rodando no teu projeto.
Eu sempre parto do princípio que, ao criar algo, eu faço com que funcione, depois vou ajustando para colocar o mesmo onde é cabível.
Detalhe: (como sempre) o @staroski está corretíssimo.

staroski

Não vejo motivo para usar Thread, basta implementar o padrão Observer (ou Listener), aí quando sua consulta termina, você notifica a janela de forma que ela saiba que pode ser fechada.

R

Eu somente fecho quanto a thread é interrompida. Porém existe um tempo em que a janela deveria aparecer

R

Se eu não usar thread o foco ficará na tela e a consulta no banco não acontecerá, pois o foco agora é a tela. Pensei em usar thread para rodar duas atividades distintas: mostrar o load e consultar no banco

R

Sim, estou a bastante dias testando. Roda sim, o que acontece é que debugando o código a tela retorna que está ativa, visível, porém ela não aparece. Este é meu problema

staroski

E porque o foco na tela interrompe a sua consulta?
Explica melhor isso aí…

R

Se instanciarmos uma tela e torná-la ela visível, agora o foco passará a ser dessa tela até que seja fechada. A aplicação só executará o consultar quando a tela for fechada, não é? Isso que aconteceu quando tentei fazer desta forma.
Por exemplo:

TelaLoad load = new TelaLoad(this, true);
    t.setVisible(true);
    dao.consultarRegistros();

Desculpe caso eu esteja equivocada, só estou tentando entender o funcionamento do que quero! Obrigado.

darlan_machado

Começa removendo a linha que irei destacar

staroski

Tá, então sua janela é modal, certo? Aí de fato o setVisible vai bloquear a execução.
Pra esse tipo de situação o padrão Observer (também chamado de Listener) vem bem a calhar.

Você pode criar uma interface DaoListener por exemplo, com métodos para notificar o inicio e término da consulta, algo mais ou menos assim:

public interface DaoListener {

    // chamado pelo Dao quando a consulta vai iniciar
    public void consultaIniciada();

    // chamado pelo Dao quando a consulta terminou
    public void consultaEncerrada();
}

Aí o método consultarRegistros da sua classe Dao vai receber um objeto DaoListener como parâmetro, assim:

public void consultarRegistros(DaoListener listener) {
    listener.consultaIniciada(); // informa o listener de que a consulta vai iniciar
    
    /*
     * Aqui vai sua implementação atual que acessa o banco e tudo mais fazendo uma operação demorada...
     */
    
    listener.consultaEncerrada(); // informa o listener de que a consulta terminou
}

Aí sua TelaLoad vai implementar a interface DaoListener, assim:

public class TelaLoad extends ClasseQueTuJaTaEstendendo implements DaoListener {

    // método da interface DaoListener
    @Override
    public void consultaIniciada() {
        // executa o setVisible em uma Thread pro método não ficar bloqueado, já que é uma janela modal
        new Thread(() -> this.setVisible(true)).start();
    }

    // método da interface DaoListener
    @Override
    public void consultaEncerrada() {
        this.setVisible(false);
    }
}

E o código onde você abre a tela e realiza a consulta, vai ficar assim:

TelaLoad load = new TelaLoad(this, true); // instancia a tela sem chamar o setVisible(true)
dao.consultarRegistros(load); // TelaLoad implementa DaoListener, então passo ela como parâmetro pro Dao

:slight_smile:

R

Removi, mas continua a mesma coisa

R

Opa, obrigado pela orientação. Vou tentar e repasso pra vocês se consegui, agradeço!

R

Olá, fiz as modificações e aparentemente deu super certo, só tenho um problema: o JDialog (a minha tela com o gif) fica em branco, ela abre e se comporta do jeito adequado porém não carrega os componentes
dialog

staroski

Infelizmente o GIF não nos mostra como o código foi implementado.

R

Se o GIF for o problema então nem precisa ser ele, mas pelo menos um JLabel com uma escrita: ‘Carregando’, mas nem isto mostra

staroski

Quis dizer que você postou uma imagem no fórum, essa imagem não nos revela como você implementou o código.
Sem ver seu código fonte, não dá pra te indicar onde está o problema. :wink:

R

Fiz o Listener:

package dao;
    public interface DaoListener {
        // chamado pelo Dao quando a consulta vai iniciar
        public void consultaIniciada();

        // chamado pelo Dao quando a consulta terminou
        public void consultaEncerrada();
    }

Aí em determinado Dao coloquei o codigo pra chamar a tela de load:

public List<Pojo> consultar(DaoListener listener) {
        listener.consultaIniciada();

 \\codigo da minha consulta

 listener.consultaEncerrada();
    return list;
    }

Aí a tela de load:

`  public class LoadTester extends javax.swing.JDialog implements DaoListener {`
        /**
         * Creates new form LoadTester
         *
         * @param parent
         * @param modal
         */
        public LoadTester(java.awt.Frame parent, boolean modal) {
            super(parent, modal);
            initComponents();
        }

    // método da interface DaoListener
    @Override
    public void consultaIniciada() {
        // executa o setVisible em uma Thread pro método não ficar bloqueado, já que é uma janela modal
        new Thread(() -> this.setVisible(true)).start();
    }

    // método da interface DaoListener
    @Override
    public void consultaEncerrada() {
            this.setVisible(false);
    }

Estilo da minha tela:
Sem%20t%C3%ADtulo

Em resumo segui os passos que me indicou, aí tenho aquele problema que te falei, os componentes da tela não carregam e ela fica em branco no tempo de execução:

dialog

staroski

Posta o código da sua consulta.

R
public List<Pojo> consultar(DaoListener listener) {
        listener.consultaIniciada();

        List<Pojo> list = new ArrayList<>();
        try {
            PreparedStatement ps = BD.getConexao().prepareStatement("SELECT * FROM pessoas");
            ResultSet rs = ps.executeQuery();
                while (rs.next()) {
                    pojo = new Pojo();
                    pojo.setId(rs.getInt("id"));
                    pojo.setNome_razaosocial(rs.getString("nome_razaosocial"));
                    pojo.setFantasia_apelido(rs.getString("fantasia_apelido"));
                    pojo.setCpf_cnpj(rs.getString("cpf_cnpj"));
                    pojo.setCelular(rs.getString("celular"));
                    pojo.setEmail(rs.getString("email"));
                    pojo.setData_nascimento(rs.getDate("data_nasc"));
                    pojo.setSexo(rs.getString("sexo"));
                    pojo.setStatus(rs.getBoolean("status"));
                    list.add(pojo);

                }
      
            } catch (Exception e) {
                JOptionPane.showMessageDialog(null, "Erro: " + e.getMessage());
            }

            listener.consultaEncerrada();
            return list;
        }
staroski

Faz o seguinte, põe um Thread.yield() a cada iteração do seu laço, isso vai dar uma chance para as outras Threads conseguirem uma fatia de tempo do processador.

while (rs.next()) {
    pojo = new Pojo();
    pojo.setId(rs.getInt("id"));
    pojo.setNome_razaosocial(rs.getString("nome_razaosocial"));
    pojo.setFantasia_apelido(rs.getString("fantasia_apelido"));
    pojo.setCpf_cnpj(rs.getString("cpf_cnpj"));
    pojo.setCelular(rs.getString("celular"));
    pojo.setEmail(rs.getString("email"));
    pojo.setData_nascimento(rs.getDate("data_nasc"));
    pojo.setSexo(rs.getString("sexo"));
    pojo.setStatus(rs.getBoolean("status"));
    list.add(pojo);
    Thread.yield(); // dar uma chance para outras Threads executarem
}
R

coloquei, a tela ainda permanece em branco (não carrega os componentes)

staroski

Como você faz pra executar a consulta e abrir a tela LoadTester?

Posta o fonte completo da classe LoadTester.

R

Ao abrir a tela gerenciar eu chamo esse método para preencher minha tabela:

LoadTester load = new LoadTester(null, true);
            for (Pojo p : PessoaDao.consultar(load)) {
                if (p != null) {
                    tabela.tmic.adicionaLinha(p);
                    tabela.tmic.fireTableDataChanged();
                }
            }

O código da LoadTester já postei acima. Desenhei ela no netbeans, os códigos que não postei foi o que o mesmo criou, mas segue de novo:

package load;
import br.com.winsite.dao.DaoListener;

public class LoadTester extends javax.swing.JDialog implements DaoListener {`
      
  /**
         * Creates new form LoadTester
         *
         * @param parent
         * @param modal
         */
        public LoadTester(java.awt.Frame parent, boolean modal) {
            super(parent, modal);
            initComponents();
        }

    // método da interface DaoListener
    @Override
    public void consultaIniciada() {
        // executa o setVisible em uma Thread pro método não ficar bloqueado, já que é uma janela modal
        new Thread(() -> this.setVisible(true)).start();
    }

    // método da interface DaoListener
    @Override
    public void consultaEncerrada() {
            this.setVisible(false);
    }


[generated code] //cod gerado pelo netbeans

 /**
     * @param args the command line arguments
     */
    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(LoadTester.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(LoadTester.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(LoadTester.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(LoadTester.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

    /* Create and display the dialog */
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            LoadTester dialog = new LoadTester(new javax.swing.JFrame(), true);
            dialog.addWindowListener(new java.awt.event.WindowAdapter() {
                @Override
                public void windowClosing(java.awt.event.WindowEvent e) {
                    System.exit(0);
                }
            });
            dialog.setVisible(true);
        }
    });
}

//Declaracao de variaveis feita pelo netbeans:
      // Variables declaration - do not modify                     
        private javax.swing.JLabel jLabel1;
        private javax.swing.JLabel jlLoad;
        // End of variables declaration
staroski

Não dá pra compilar sua classe se não postar o código completo.

R
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package load;

import dao.DaoListener;

/**
 *
 *
 */
public class LoadTester extends javax.swing.JDialog implements DaoListener {


    /**
     * Creates new form LoadTester
     *
     * @param parent
     * @param modal
     */
    public LoadTester(java.awt.Frame parent, boolean modal) {
        super(parent, modal);
        initComponents();
    }

//     método da interface DaoListener
    @Override
    public void consultaIniciada() {
        new Thread(() -> this.setVisible(true)).start();
    }

    // método da interface DaoListener
    @Override
    public void consultaEncerrada() {
            this.setVisible(false);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jlLoad = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);

        jlLoad.setBackground(new java.awt.Color(0, 0, 0));
        jlLoad.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
        jlLoad.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jlLoad.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imagens/reload_60.gif"))); // NOI18N
        jlLoad.setCursor(new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR));

        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setText("Carregando...");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                    .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jlLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 153, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(134, 134, 134)
                .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(jlLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 123, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(0, 55, Short.MAX_VALUE)))
        );

        setSize(new java.awt.Dimension(189, 217));
        setLocationRelativeTo(null);
    }// </editor-fold>                        

    /**
     * @param args the command line arguments
     */
    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(LoadTester.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(LoadTester.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(LoadTester.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(LoadTester.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the dialog */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                LoadTester dialog = new LoadTester(new javax.swing.JFrame(), true);
                dialog.addWindowListener(new java.awt.event.WindowAdapter() {
                    @Override
                    public void windowClosing(java.awt.event.WindowEvent e) {
                        System.exit(0);
                    }
                });
                dialog.setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jlLoad;
    // End of variables declaration                   
}
staroski

Experimenta mudar seu método consultaIniciada para usar o invokeLater ao invés de Thread:

@Override
public void consultaIniciada() {
    SwingUtilities.invokeLater(() -> this.setVisible(true));
}
R

Agora a tela é carregada corretamente (aparece os componentes), porém ela só aparece depois que a consulta já foi feita.

staroski

Então sua consulta está bloqueando tudo, tenta realizar a consulta em uma Thread separada:

public List<Pojo> consultar(DaoListener listener) {
    listener.consultaIniciada();

    List<Pojo> list = new ArrayList<>();
    try {
        Thread thread = new Thread(() -> realizarConsulta(list));
        thread.start();
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    listener.consultaEncerrada();
    return list;
}

private void realizarConsulta(List<Pojo> list) {
    try {
        PreparedStatement ps = BD.getConexao().prepareStatement("SELECT * FROM pessoas");
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            Pojo pojo = new Pojo();
            pojo.setId(rs.getInt("id"));
            pojo.setNome_razaosocial(rs.getString("nome_razaosocial"));
            pojo.setFantasia_apelido(rs.getString("fantasia_apelido"));
            pojo.setCpf_cnpj(rs.getString("cpf_cnpj"));
            pojo.setCelular(rs.getString("celular"));
            pojo.setEmail(rs.getString("email"));
            pojo.setData_nascimento(rs.getDate("data_nasc"));
            pojo.setSexo(rs.getString("sexo"));
            pojo.setStatus(rs.getBoolean("status"));
            list.add(pojo);
            Thread.yield();
        }
    } catch (Exception e) {
        JOptionPane.showMessageDialog(null, "Erro: " + e.getMessage());
    }
}
R

A tela volta a não carregar os componentes, aparece em branco

staroski

Então tem algum problema de sincronização entre suas consultas e a Thread de renderização do Swing.

R

Não tenho ideia do que pode ser, por isso socorri ao fórum. Já tentei vários jeitos diferentes mas não consegui fazer esse bendito load

staroski

Poderias tentar substituir o Thread.yield() por um Thread.sleep(1).

R

A tela ainda fica em branco :frowning:

staroski

Como está implementado o método main de sua aplicação?

R

Quando o sistema inicia eu chamo essa classe que abre minha tela principal:

package principal;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.UIManager;


public class Aplicacao {
    public static void main(String Args[]) throws Exception {
        try {
            JFrame.setDefaultLookAndFeelDecorated(true);

            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

            TelaPrincipal tela = new TelaPrincipal();
            tela.setVisible(true);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, e.getMessage());
        }
    }
}
R

Alguém?

staroski

Tem algum processo bloqueando a thread do Swing.
Teria que ver todas suas classes pra identificar exatamente o ponto onde está o problema.

Criado 8 de maio de 2019
Ultima resposta 22 de mai. de 2019
Respostas 39
Participantes 3