JMS Fila para JTable Atualização [Agora recebendo exceção após as alterações]
Pergunta
Eu estou escrevendo meu próprio navegador JMS e eu sou golpeado na atualização JTable de mensagens de servidores JMS. Eu tentei Este abaixo obras Logis, mas o seu tempo real não atualizar, meios eu gostaria de exibir cada linha adicionada para JTable imediatamente quando seu adicionada a partir QueueBrowser para LinkedList. AbstractTableModel
TableModelListener
para fazer atualização JTable quando os dados adicionados em LinkedList.
Eu atualizei o código de acordo com as sugestões abaixo.
Estou fazendo algo errado? Alguém pode me ajudar?
QueueBrowser qb = session.createBrowser(q);
MsgTable mt = (MsgTable) queueTable.getModel();
mt.load(qb.getEnumeration(),mt);
qb.close();
class MsgTable extends AbstractTableModel implements TableModelListener{
final String[] columnNames = { "#", "Timestamp", "Type", "Mode",
"Priority" };
public void setRowSize(){
}
LinkedList queueList = new LinkedList();
public int getRowCount() { if (queueList == null) { return 0; } else { return queueList.size();}}
public int getColumnCount() { return columnNames.length;}
public String getColumnName(int column) {return columnNames[column];}
public Object getValueAt(int row, int column) {
if(queueList == null){
return null;
}
Message m = (Message) queueList.get(row);
...
}
void load(Enumeration e,MsgTable mt) {
mt.addTableModelListener(this);
while(e.hasMoreElements()){
queueList.add(e.nextElement());
}
fireTableDataChanged();
}
Message getMessageAtRow(int row) {
if (queueList == null)
return null;
return ((Message) queueList.get(row));
}
@Override
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
fireTableDataChanged();
}
}
e recebendo essa exceção.
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)
É errado?
Solução
Para meu conhecimento, o seu JTable
deve atualizar automaticamente quando uma alteração no TableModel
acontece. Confira o tutorial sol na trabalhar com tabelas especialmente a seção sobre de escuta para alterações de dados , isso pode ajudar. Dito isto, eu tenho um par de observações:
-
Eu realmente não entendo o método
getValueAt(int row, int col)
. você não deve ter a linha-th mensagem eo col-th atributo da mensagem? -
Eu adicionaria um
addRow(...)
eaddRows(...)
a implementaçãoMsgTable
de TableModel para atualizar o modelo interno e acionar o evento apropriado. -
Você não precisa implementar
TableModelListener
(eu não posso ver qualquer chamada paraaddTableModelListener(...)
de qualquer maneira)
(EDIT:. O OP actualiza a sua pergunta com novo código então eu estou atualizando a minha resposta em conformidade abaixo)
Você modificou a assinatura load(...)
e do corpo para adicionar uma chamada para addTableModelListener(...)
e eu acho que ambas as modificações não estão corretas.
Sobre o addTableModelListener (... ) , a documentação diz:
Adiciona um ouvinte para a lista que é notificado cada vez que uma mudança para o modelo de dados ocorre.
E sobre os vários métodos fireFooXxx(...)
:
notifica todos os ouvintes que [a mudaram ocorreu]
Assim, com a seguinte implementação de um TableModelListener
:
@Override
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
fireTableDataChanged();
}
Você vai acabar fazendo chamadas recursivas infinitas (o ouvinte é notificado por uma mudança e disparar um evento que irá notificá-lo de novo etc), daí o java.lang.StackOverflowError .
Na verdade, eu ainda acho que você não precisa de um TableModelListener
(e do jeito que você está registrando não é correto IMO, consulte Ouvir para alterações de dados no tutorial Sun). Eu, portanto, remover a implements TableModelListener
e bastante implementar o método load(...)
assim:
void load(Enumeration e) {
while(e.hasMoreElements()) {
queueList.add(e.nextElement());
}
fireTableDataChanged();
}
Outras dicas
pontos casal um para adicionar à consideração:
- seu método
load(Enumeration e)
não precisa jogar umJMSException
, como você está apenas interagindo sobre umEnumeration
. -
você deve garantir que o seu disparo de eventos é feito dentro da EDT. Isso pode ser tão simples como embalar sua chamada para
load
em um executável e soltando-aSwingUtilities.invokeLater()
:MsgTable mt = (MsgTable) queueTable.getModel(); final Enumeration e = qb.getEnumeration(); SwingUtilities.invokeLater(new Runnable() { public void run() { mt.load(e); } });
uma maneira de-se o desempenho seria apenas para chamar fireTableDataChanged () no final do método de carga (), em oposição a após cada linha é carregado.
que deve ajudar.
ou seja:
void load(Enumeration e) throws JMSException {
while(e.hasMoreElements()){
queueList.add(e.nextElement());
fireTableDataChanged();
}
}
para
void load(Enumeration e) throws JMSException {
boolean dataAdded = false;
while(e.hasMoreElements()){
queueList.add(e.nextElement());
dataAdded = true;
}
fireTableDataChanged();
}
Bem, o bom design é criar um método addRow (...) que recebe uma linha de dados e atualiza o armazenamento interno de seu TableModel. Este método deveria então invocar o método fileTableRowsInserted (). Seu método getValueAt () também não faz sentido. De acordo com o modelo que você tem 5 colunas de dados, mas você nunca verificar a variável de coluna para retornar o objeto coluna adequada.
Dê uma olhada no código fonte do DefaultTableModel para ver como um insertRow () e getValueAt () método pode ser codificada.