GUJ Discussões   :   últimos tópicos   |   categorias   |   GUJ Respostas

Gráficos jFreeChart: Thread que atualiza o gráfico trava caso o ResultSet seja nulo

mysql
java
programação
threads
Tags: #<Tag:0x00007f75fafa6c30> #<Tag:0x00007f75fafa6af0> #<Tag:0x00007f75fafa69b0> #<Tag:0x00007f75fafa6870>

#1

Estou montando uma aplicação java desktop onde tenho uma tabela que é alimentada hora a hora, ai possuo um Jframe que contem alguns gráficos jFreeChart estes gráficos coletam os dados da tabela e se atualizam a cada segundo para apresentação em um monitor.

PROBLEMA: Ao virar o dia, ou seja, após a meia noite o gráfico faz a consulta na tabela porém como ainda não foi alimentada (só será alimentada as 01h) o ResultSet retorna nulo e Thread responsável pela atualização trava e não reinicia mesmo após incluirmos os próximos registros da próxima hora, vou colocar abaixo partes do código passo a passo:

Classe principal:

public class formDashProducao extends javax.swing.JFrame {
public formDashProducao() throws SQLException {
        initComponents();
        agora(); //Aqui inicia uma Thread que seta e atualiza a data "dd/mm/aaa" em um jLabel na qual é utilizado como filtro para a consulta SQL
        atualiza(); //Aqui chama uma outra Thread que possui o método que gera os Gráficos

Thead agora()

//Metodo de tempo para atualizar a data e hora dos jLabels principais da aplicação
    public void agora() {
        new Thread() {
            @Override
            @SuppressWarnings("SleepWhileInLoop")
            public void run() {
                while (true) {
                    try {
                        String data = dt.format(new Date());
                        String hora = hr.format(new Date());
                        txtData.setText(data);
                        txtHora.setText(hora);
                        sleep(1);
                    } catch (InterruptedException ex) {
                        System.out.println(ex);
                    }
                }
            }
        }.start();
    }

Thread atualiza()

//Metodo de tempo para chamar a construção dos gráficos e atualiza-los a cada segundo
        public void atualiza() {
            new Thread() {
                @Override
                @SuppressWarnings("SleepWhileInLoop")
                public void run() {
                    while (true) {
                        try {
                            graficos(); //Aqui chama a construção dos gráficos e atualiza-os
                            sleep(1000);
                        } catch (InterruptedException ex) {
                            System.out.println(ex);
                        }
                    }
                }
            }.start();
        }

Método graficos() responsável pela chamada e construção dos gráficos no Jframe

//Metodo para recarregar os gráficos
        public void graficos() {
            //Recarrega os gráficos
            painel1.removeAll();
            painel2.removeAll();
            painel3.removeAll();
            painel5.removeAll();
            try {
                BarChartPEhh("", "PE - Peças embaladas Hora a Hora", txtData.getText(), painel1); //Primeiro gráfico
                BarChartPEObRe("", "PE - Objetivo vs Realizado", txtData.getText(), painel2);          //Segundo gráfico
                PieChartPECompTurno("", "PE - Peças embaladas por Turno", txtData.getText(), painel3);
                BarChartPEMedHh("", "PE - Media de peças embaladas Hh", txtData.getText(), painel5);
                //ConclusaoDia(txtData.getText());
                //PerformanceT1(txtData.getText());
                //PerformanceT2(txtData.getText());
                //PerformanceGeral(txtData.getText());
            } catch (SQLException ex) {
                Logger.getLogger(formDashProducao.class.getName()).log(Level.SEVERE, null, ex);
                System.err.println(ex);
            }
        }

Construção do primeiro gráfico chamado ali no código acima graficos()
BarChartPEhh("", “PE - Peças embaladas Hora a Hora”, txtData.getText(), painel1); //Primeiro gráfico

/////////////////////INICIO GRÁFICO BARRA PE hora a hora////////////////////////
//Criando e personalizando o gráfico de Barra (PE hora a hora)
        private JFreeChart createChartPEhh(CategoryDataset dataset, String title) {
            JFreeChart chart = ChartFactory.createBarChart(
                    title,
                    "",
                    "",
                    dataset,
                    PlotOrientation.VERTICAL,
                    true, true, false);

            //Personalizando o título superior principal
            chart.getTitle().setHorizontalAlignment(HorizontalAlignment.CENTER);
            chart.getTitle().setFont(new Font("SansSerif", Font.PLAIN, 15));
            chart.getTitle().setFrame(BlockBorder.NONE);

            //Personalizando a área de plotagem do gráfico
            CategoryPlot plot = (CategoryPlot) chart.getPlot();
            plot.setBackgroundPaint(Color.white);
            plot.setDomainGridlinePaint(Color.white);
            plot.setRangeGridlinePaint(Color.white);
            plot.setOutlineVisible(false);
            plot.setNoDataMessage("Aguarde até a proxima hora ou verifique o servidor");

            //Personalizando as barras do gráfico
            BarRenderer bar = (BarRenderer) plot.getRenderer();
            bar.setGradientPaintTransformer(null);
            bar.setBarPainter(new StandardBarPainter());
            bar.setSeriesPaint(0, new java.awt.Color(116, 124, 137));

            //Colocando legenda nas barras
            bar.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
            bar.setBaseItemLabelsVisible(true);
            bar.setBaseItemLabelFont(new Font("SansSerif", Font.PLAIN, 11));
            bar.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER));

            // Ocultando o eixo Y lateral esquerdo que contem os valores
            NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
            rangeAxis.setVisible(false);

            // Formatando o eixo X inferior que contem as horas
            CategoryAxis domainAxis = plot.getDomainAxis();
            domainAxis.setTickLabelsVisible(true);
            domainAxis.setTickLabelFont(new Font("SansSerif", Font.PLAIN, 10));

            //Personalizando a legenda inferior
            chart.getLegend().setFrame(BlockBorder.NONE);
            chart.getLegend().setItemFont(new Font("SansSerif", Font.PLAIN, 11));
            chart.getLegend().setVerticalAlignment(VerticalAlignment.CENTER);
            chart.getLegend().setHorizontalAlignment(HorizontalAlignment.CENTER);

            return chart;
        }

//Criando Dataset para puxar os dados da table pe e colocar no gráfico de barra (PE hora a hora)
        private CategoryDataset createDatasetPEhh(String criterio1) throws SQLException {
            com.mysql.jdbc.Connection conn = ConnectionMySQL.getConnection();
            // Consulta SQL para trazer os dados e alimentar o grafíco 
            String query = "select LEFT(peData,10) AS peData, "
                    + "SUBSTRING(peData,11,3) AS peHora, "
                    + "SUM(peEmbalado) AS peEmbalado "
                    + "FROM pe "
                    + "WHERE peData LIKE '%" + criterio1 + "%'"  //Esse critério ele pega a data setada no jLabel da Thread agora()
                    + "GROUP BY peHora";

            // Criando java statement
            Statement st = conn.createStatement();

            // Executando a query, e trazendo o resultset
            ResultSet rs = st.executeQuery(query);

            // Setando os dados para o gráfico
            DefaultCategoryDataset result = new DefaultCategoryDataset();
            if (rs == null || !rs.first()) { //Tentei fazer isso caso nulo mas o problema continua
                throw new NullPointerException("Destino não pode ser nulo!"); 
            } else {
                do {
                    result.addValue(rs.getInt("peEmbalado"), rs.getString("peData"), rs.getString("peHora"));
                } while (rs.next());
            }
            st.close();
            return result;
        }

//Criando o gráfico de barra (PE hora a hora) finalizado e colocando no Jframe
        public void BarChartPEhh(String applicationTitle, String chartTitle, String criterio, javax.swing.JPanel painel) throws SQLException {
            // Isso irá criar o conjunto de dados
            CategoryDataset dataset = createDatasetPEhh(criterio);

            // com base no conjunto de dados que criamos o gráfico
            JFreeChart chart = createChartPEhh(dataset, chartTitle);

            // vamos colocar o gráfico em um painel        
            ChartPanel chartPanel = new ChartPanel(chart);

            // default tamanho
            chartPanel.setPreferredSize(new java.awt.Dimension(200, 200));

            //Adicionando o Gráfico dentro do painel passado 
            painel.add(chartPanel);
            painel.repaint();
            painel.revalidate();
        }
////////////////////////FIM GRÁFICO BARRA PE hora a hora////////////////////////

Construção do segundo gráfico chamado chamado lá no código graficos()
BarChartPEObRe("", “PE - Objetivo vs Realizado”, txtData.getText(), painel2); //Segundo gráfico

/////////////////INICIO GRÁFICO BARRA PE Objetivo vs Realizado//////////////////
//Criando e personalizando o gráfico de Barra (PE Objetivo vs Realizado)
        private JFreeChart createChartPEObRe(CategoryDataset dataset, String title) {
            JFreeChart chart = ChartFactory.createBarChart(
                    title,
                    "",
                    "",
                    dataset,
                    PlotOrientation.VERTICAL,
                    true, true, false);

            //Personalizando o título superior principal
            chart.getTitle().setHorizontalAlignment(HorizontalAlignment.CENTER);
            chart.getTitle().setFont(new Font("SansSerif", Font.PLAIN, 15));
            chart.getTitle().setFrame(BlockBorder.NONE);

            //Personalizando a área de plotagem do gráfico
            CategoryPlot plot = (CategoryPlot) chart.getPlot();
            plot.setBackgroundPaint(Color.white);
            plot.setDomainGridlinePaint(Color.white);
            plot.setRangeGridlinePaint(Color.white);
            plot.setOutlineVisible(false);
            plot.setNoDataMessage("Ocorreu um erro inesperado com a conexão com o banco de dados. Favor verificar com TI");

            //Personalizando as barras do gráfico
            BarRenderer bar = (BarRenderer) plot.getRenderer();
            bar.setItemMargin(-0.9);
            bar.setGradientPaintTransformer(null);
            bar.setBarPainter(new StandardBarPainter());
            bar.setSeriesPaint(0, new java.awt.Color(232, 232, 232));//Objetivo
            bar.setSeriesPaint(1, new java.awt.Color(74, 112, 139));//Realizado 74, 112, 139

            //Colocando legenda nas barras
            bar.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
            bar.setBaseItemLabelsVisible(true);
            bar.setBaseItemLabelFont(new Font("SansSerif", Font.TRUETYPE_FONT, 16));
            bar.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER));

            // Ocultando o eixo Y lateral esquerdo que contem os valores
            NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
            rangeAxis.setVisible(false);

            // Formatando o eixo X inferior que contem as horas
            CategoryAxis domainAxis = plot.getDomainAxis();
            domainAxis.setTickLabelsVisible(true);
            domainAxis.setTickLabelFont(new Font("SansSerif", Font.PLAIN, 10));

            //Personalizando a legenda inferior
            chart.getLegend().setFrame(BlockBorder.NONE);
            chart.getLegend().setItemFont(new Font("SansSerif", Font.PLAIN, 11));
            chart.getLegend().setVerticalAlignment(VerticalAlignment.CENTER);
            chart.getLegend().setHorizontalAlignment(HorizontalAlignment.CENTER);

            return chart;
        }

//Criando Dataset para puxar os dados da table pe e colocar no gráfico de barra (PE Objetivo vs Realizado)
        private CategoryDataset createDatasetPEObRe(String criterio1) throws SQLException {
            com.mysql.jdbc.Connection conn = ConnectionMySQL.getConnection();

            // Consulta SQL para trazer os dados e alimentar o grafíco 
            String query = "SELECT LEFT(peData,10) AS peData, "
                    + "Round(AVG(peObjetivo),0) AS peObjetivo, "
                    + "SUM(peEmbalado) AS peRealizado "
                    + "FROM pe "
                    + "WHERE peData LIKE '%" + criterio1 + "%'"; //Esse critério ele pega a data setada no jLabel da Thread agora()

            // Criando java statement
            Statement st = conn.createStatement();

            // Executando a query, e trazendo o resultset
            ResultSet rs = st.executeQuery(query);

            // Setando os dados para o gráfico
            DefaultCategoryDataset result = new DefaultCategoryDataset();
            if (rs == null || !rs.first()) {
                result.addValue(0, "Objetivo", criterio1);
                result.addValue(0, "Realizado", criterio1);
            } else {
                do {
                    result.addValue(rs.getInt("peObjetivo"), "Objetivo", rs.getString("peData"));
                    result.addValue(rs.getInt("peRealizado"), "Realizado", rs.getString("peData"));
                } while (rs.next());
            }
            st.close();
            return result;
        }

//Criando o gráfico de barra (PE Objetivo vs Realizado) finalizado e colocando no Jframe
        public void BarChartPEObRe(String applicationTitle, String chartTitle, String criterio, javax.swing.JPanel painel) throws SQLException {
            // Isso irá criar o conjunto de dados
            CategoryDataset dataset = createDatasetPEObRe(criterio);

            // com base no conjunto de dados que criamos o gráfico
            JFreeChart chart = createChartPEObRe(dataset, chartTitle);

            // vamos colocar o gráfico em um painel        
            ChartPanel chartPanel = new ChartPanel(chart);

            // default tamanho
            chartPanel.setPreferredSize(new java.awt.Dimension(200, 200));

            //Adicionando o Gráfico dentro do painel passado 
            painel.add(chartPanel);
            painel.repaint();
            painel.revalidate();
        }
///////////////////FIM GRÁFICO BARRA PE Objetivo vs Realizado///////////////////

Enquanto possuo dados na tabela para exibir no dia, ele funciona e atualiza perfeitamente, quando vira o dia ele faz a consulta SQL na nova data porém como ainda não consta dados o ResultSet retorna nulo e para a Thread e mesmo incluindo novos dados o a Thread não retoma e sou obrigado a abrir e fechar novamente a aplicação.

Quando conseguir resolver estarei postando o código completo aqui para compartilhamento.


#2

Você precisa verificar se o seu ResultSet está vazio e não se ele está nulo, use como exemplo o seguinte:

ResultSet rs = st.executeQuery(query);

rs.last();

if(rs.getRow() == 0){
     // ResultSet vazio
}else{
     // ResultSet com dados
     rs.first();
}

Não esqueça de sempre chamar o first() depois do last().

Espero ter ajudado.


#3

Boa noite!

Obrigado pelas dicas, resolvi trocando a Thread por ActionListener:

private void AtualizaDados() {
        ActionListener action = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                refresh(txtData.getText());
            }
        };
        this.timerHora = new Timer(velocidadeHora, action);
        this.timerHora.start();
    }