[RESOLVIDO] DefaultTableCellRenderer -> Processamento elevado

11 respostas
RenataFA

Olá pessoal!

Demorei mas apareci! :oops:

Seguinte, tenho uma classe MinhaTableCellRenderer que extends DefaultTableCellRenderer.

No método getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column), eu implementei coisinhas que preciso, aquelas conhecidas sabe? Mudar a cor, mudar o tamanho da linha, fonte, etc, etc…

Meu problema está no fato de que isso está elevando o processamento demais. Então por ex, suponhamos que eu abro o Gerenciador de tarefas do Windows e o uso de CPU está em 3% (com meu sistema aberto, tudo rodando). Ai eu abro uma tela que tem um JTable usando esse Renderer e adivinhem? O processamento vai pra 30%!!!

Tenho casos em que qdo mais de um usuário acessa a tal tela (via comunicação, TS por ex), o consumo de CPU do servidor de aplicação sobe até dar o topo e travar tudo.

Sei que o tal método getTableCellRendererComponent fica sendo chamado seguidamente enquanto o JTable está sendo apresentado. Coloquei um “sysout” dentro dele e é chamado seguidamente, o tempo todo.

Por acaso alguém tem alguma dica do que posso fazer pra continuar com meu JTable personalizado (com cores, etc, etc…) e reduzir esse processamento de CPU? Não tem como eu de alguma forma fazer as personalização das linhas só a primeira vez que ela for acessada? É um caso onde o conteúdo do JTable não vai ser alterado, ele é carregado uma vez e pronto, não muda, é uma espécie de consulta, ele não precisaria ficar renderizando o tempo todo.

Alguma dica?

Grata,
Renata

11 Respostas

E

Eu tive um problema parecido com esse (mas eu não troquei o DefaultFableCellRenderer). O problema é o seguinte: quando alguma informação é atualizada na sua tabela,
provavelmente você chama um “fireAlgumaCoisa”.

O problema é que esse “fireAlgumaCoisa” costuma redesenhar a tela inteira, já que ele não sabe se é para redesenhar apenas uma célula ou todas.

Eu até usei o GlazedLists, mas nesse caso a velocidade de redesenho da tela precisava ser tão absurdo (e nem precisava - não tenho como acompanhar uma alteração em uma célula se ela for mais frequente que 10 vezes por segundo) e então desabilitei o recurso de redesenho do Glazed Lists.

Nesse ponto, eu simplesmente liguei um timer de 100 ms para redesenhar a tela completa, começou a gastar menos CPU que se eu tratasse todos os fireAlgumaCoisa.

RenataFA

Poxa amigo, me explica melhor o lance do “fireAlgumaCoisa” que eu não entendi.

Onde ele estaria chamando isso? Desculpe, mas não entendi msm. E o que vc disse parece ser bem plausível com a situação que estou enfrentando.

Grata,
Renata

E

Digamos que você tenha usado um DefaultTableModel (argh). Se você fez isso, a cada vez que você chama o setValueAt para atualizar uma célula da sua tabela, irá disparar um evento do tipo tableChanged. Só que esse evento indica que a tabela mudou (não que apenas uma célula mudou). Nessa brincadeira, o que ocorre é que a tabela é toda redesenhada.
Se você usar um outro TableModel você pode ajustar esse comportamento.
E os métodos “fireAlgumaCoisa” estão documentados em:
http://download.oracle.com/javase/7/docs/api/javax/swing/table/AbstractTableModel.html

josue_carrecon

olha, jtable não eh facil, toh apanhando com uma formatação de data que tah um saquinho.

RenataFA

Então entanglement, não uso o DefaultTableModel não. Tenho uma classe que extends o AbstractTableModel. Nela eu já trato coisas que eu preciso.

Vc mencionou que cada vez que chamo o setValueAt ele dispara o evento tableChanged e toda a JTable é redesenhada. Acho estranho pq eu não uso o setValueAt o tempo todo. Como falei, é uma tela de consulta, então eu faço o select no BD, adiciono o resultado no model do meu JTable usando addRow e só! Parei! Não mexo em mais nada nos dados, a não ser que o usuário especifique um novo filtro e mandei pesquisar novamente (ai eu limpo tudo e refaço o processo de pesquisa com o novo filtro).

Porém, notei que mesmo com a tela parada, sem mexer em nada, fica rodando o tal Renderer o tempo todo, e meu processamento vai pro céu!

Eu não conhecia os métodos “fireAlgumaCoisa”. Vou tentar sobreescrevê-los na minha classe Model pra ver no que dá.
Vc tem alguma dica de como posso fazer esse tal controle?

Grata,
Renata

E

Realmente estranho. Só uma perguntinha - o seu Renderer é algo derivado de JLabel ou é uma outra coisa? Só por curiosidade. Parece que alguma coisa está indicando que o Renderer não completou algum redesenho ou coisa parecida, e é por isso que o JTable está constantemente repintando a tela.

RenataFA

entanglement, consegui entender onde está a caca, mas não estou conseguindo resolver. Vou dar uma exemplificada pra vc entender como uso, quem sabe vc me dá uma dica de como resolver.

Qdo estou criando meu JTable e colocando tudo que preciso, coloco o renderer assim: (suponha que meuTable seja o JTable e meuRenderer seja um TableCellRendererPadrao)

meuTable.getColumnModel().getColumn(0).setCellRenderer(meuRenderer);

O TableModel de meuTable, extends AbstractTableModel.

TableCellRendererPadrao é minha classe que extends DefaultTableCellRenderer, vou colocar a carcaça dela aqui pra vc ver:

public class TableCellRendererPadrao extends DefaultTableCellRenderer {
	
	public TableCellRendererPadrao(){
		super();
		// tratamentos aqui que não importam
	}

	
	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
		
		// faço aqui dentro várias coisas, mudo cor, alinhamento, etc, etc... diversas coisas que não interessam 

		// ai, aqui que  dando a caquinha, eu vou alterar o tamanho da linha (sabe igual excel? cada linha na altura necessária pra mostrar o conteúdo)

		table.setRowHeight(row, altura); // ajustar o altura da linha no JTable !!!!!!! ATENÇÃO PRA ESSA LINHA !!!!!!
			
		super.setSize(super.getWidth(), altura); // ajusto a altura da linha no component

		return super.getTableCellRendererComponent(table, conteudo.toString(), isSelected, hasFocus, row, column);
	}
	
}

Tá vendo a linha que eu marquei com um ATENÇÃO? Qdo eu dou esse comando, pra mudar a altura da linha, ele chama o Renderer, e o Renderer que tá dando esse comando, que chama o Renderer que dá o comando que chama o Renderer................. tendeu? Loop!!! De dentro do meu Renderer eu chamo o comando pra ajustar a altura da linha que justamente chama meu Renderer denovo! Por isso a loucura do Loop! Agora fez sentido tudo!!!

Agora me ajuda a resolver... pq assim, sei que é ai o problema, se eu comento, não fica em loop, não sobrecarrega processador, fica tudo certinho. Mas claro, não posso apenas comentar, pq preciso desse ajuste de altura nas linhas pra não ficar tudo esmagado.

Eu tentei, antes de dar aquela linha de comando que marquei com ATENÇÃO, remover os Renderes de todas as colunas do meu JTable, acionar o comando, e depois voltar os Renderes. Porém, sem sucesso, eu fiz exatamente o que te falei e mesmo assim entrou no tal loop. A impressão que dá é de que não adiantou eu remover os Renderes pq ele não chama já de imediato, ele espera terminar de montar todas as linhas que couberam na tela, pra depois chamar o Renderer pra todas denovo. E ai denovo, e denovo, e denovo.... (dei um "sysout" e é isso que ele faz, fica em loop com as linhas que eu estou na tela).

Alguma sugestão de como posso falar pra ele não refazer nesse caso?!

Grata,
Renata

E

Hum…

table.setRowHeight(row, altura);

Daria para fazer algo como

if (altura != table.getRowHeight (row)) 
           table.setRowHeight (row, altura);

Acho que setRowHeight está sempre forçando o redesenho da tela, mesmo que a altura não seja alterada.
Outra coisa: suponha que haja várias células na mesma linha com alturas diferentes. Será que você não precisa determinar o máximo delas (por exemplo)? Do jeito que está feito, você vai deixar a linha com a altura da última célula da tela. Algo parecido com:

int maxAltura;
     if (column == 0) maxAltura = altura; else maxAltura = Math.max (altura, maxAltura);
      if (maxAltura != table.getRowHeight (row)) 
           table.setRowHeight (row, maxAltura);

Hum…

RenataFA

Não não… tudo isso que vc falou eu já trato.

Já verifico se a altura precisa msm ser mudada, já verifico a altura da maior célula da linha, tudo feitinho. É que só postei a linha em que eu de fato preciso alterar o tamanho. Tendeu?

E sim, como vc disse, o setRowHeigth está forçando o redesenho da tela.

Como fazer pra que ele não force?!

RenataFA

Solução!!!

Só pra ficar registrado aqui, pra quem precisar depois de mim.

Então entanglement, ele não força o redesenho da tela se a altura não for alterada, quero dizer, se eu não settar o valor. O problema era que eu estava settando!

Meu erro era MUITO simples, mas eu juro que não enxergava (e nem tinha como vc enxergar, pq não estava no trecho de código que eu postei).
Simples, invés de usar:

if (table.getRowHeight(row) != altura)

que seria o correto, inclusive vc postou desta forma.
Eu estava usando assim:

if (table.getRowHeight() != altura)

Desgraça do ctrl+space!!! Puxou o método errado e eu nem vi! E isso desde antes de eu postar aqui a primeira vez! Então ele sempre comparava minha altura com a altura padrão de linhas do JTable, e sempre lógico, precisava mudar denovo, o que fazia com q ele fizesse a renderização novamente, e ai o loop que já falamos.

Perdi um tempão tentando encontrar quem era que chamava a renderização, pra tentar impedir, olhei cada método… alias, segundo a API, é o próprio setRowHeight() que chama a renderização.

Enfim, acertei esse detalhe besta q eu não estava enxergando e pronto! Ele passa uma vez, na segunda ele já está com o valor alterado então não passa e tudo funciona!

Obrigada a quem me ajudou, e fica ai a dica pra quem precisar… rs… :wink:

T+,
Re

E

Parabéns.

Criado 20 de outubro de 2011
Ultima resposta 21 de out. de 2011
Respostas 11
Participantes 3