Load com threads

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.

Mas você já viu isso funcionando?

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

Provavelmente pelo fato de você fechar ela, veja:

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

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.

1 curtida

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.

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

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

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

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

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.

Começa removendo a linha que irei destacar

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:

1 curtida

Removi, mas continua a mesma coisa

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

1 curtida

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

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

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

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:

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