import
java.util.LinkedList;
import
java.util.List;
import
javax.swing.SwingUtilities;
import
javax.swing.table.AbstractTableModel;
/**
*
* @date 17/10/2012
*/
public
class
SizeFixedStackTableModel
extends
AbstractTableModel {
public
static
interface
RecordRenderer
int
getColumnCount();
/**
*
* @param record
* @param column
* @return
* @throws IndexOutOfBoundsException when column is not valid
* {@code ( column < 0 || column >= getColumnCount() )}
*/
Object getValueAt(R record,
int
column);
}
private
final
RecordRenderer
super
R> recordRenderer;
private
volatile
int
size;
private
List
public
SizeFixedStackTableModel(RecordRenderer
super
R> recordRenderer,
int
size) {
if
( recordRenderer ==
null
)
throw
new
NullPointerException();
if
( size <
0
)
throw
new
IllegalArgumentException();
this
.recordRenderer = recordRenderer;
this
.size = size;
this
.records =
new
LinkedList
}
@Override
public
int
getRowCount() {
assert
SwingUtilities.isEventDispatchThread();
return
Math.min(size, records.size());
}
@Override
public
int
getColumnCount() {
assert
SwingUtilities.isEventDispatchThread();
return
recordRenderer.getColumnCount();
}
@Override
public
Object getValueAt(
int
rowIndex,
int
columnIndex) {
assert
SwingUtilities.isEventDispatchThread();
// potentially throws IndexOutOfBoundsException
R record = records.get(rowIndex);
return
recordRenderer.getValueAt(record, columnIndex);
}
public
void
setSize(
int
size) {
if
( size <
0
)
throw
new
IllegalArgumentException(
"Invalid table model size: "
+ size);
if
(
this
.size == size )
return
;
this
.size = size;
fireTableDataChanged();
}
public
void
insert(
final
R record) {
if
( SwingUtilities.isEventDispatchThread() ) {
records.add(
0
, record);
fireTableDataChanged();
}
else
{
SwingUtilities.invokeLater(
new
Runnable() {
@Override
public
void
run() {
insert(record);
}
});
}
}
}
import
java.awt.BorderLayout;
import
java.text.DateFormat;
import
java.text.SimpleDateFormat;
import
java.util.Date;
import
java.util.concurrent.CountDownLatch;
import
javax.swing.JFrame;
import
javax.swing.JTable;
import
javax.swing.SwingUtilities;
/**
*
* @date 17/10/2012
*/
public
class
TestTable {
public
static
void
main(String[] args)
throws
Exception {
final
int
rows =
30
;
final
SizeFixedStackTableModel model =
new
SizeFixedStackTableModel(
new
SizeFixedStackTableModel.RecordRenderer() {
private
final
DateFormat format =
new
SimpleDateFormat(
"yyyy-MM-dd hh:mm:ss:SSS"
);
@Override
public
int
getColumnCount() {
return
2
;
}
@Override
public
Object getValueAt(Date record,
int
column) {
if
( column ==
0
)
return
format.format(record);
else
if
( column ==
1
)
return
record.getTime();
else
throw
new
IndexOutOfBoundsException(
"Invalid column : "
+ column);
}
}, rows);
final
CountDownLatch cd =
new
CountDownLatch(
1
);
SwingUtilities.invokeLater(
new
Runnable() {
@Override
public
void
run() {
JFrame f =
new
JFrame(
"Test Table Model"
);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTable table =
new
JTable(model);
f.getContentPane().add(table, BorderLayout.CENTER);
f.setSize(
800
, table.getRowHeight() * rows +
50
);
f.setLocationRelativeTo(
null
);
f.setVisible(
true
);
cd.countDown();
}
});
cd.await();
while
(
true
) {
Thread.sleep(
500
);
model.insert(
new
Date());
}
}
}