[编辑:我最初的回答有一些错误和影响。同时,我根据各种示例找到了一个更优雅的解决方案。]
此解决方案基于http://www.coderanch.com/t/336033/GUI/java/MultiLine-JTable - 我做了一些错误修复,不过(主要是:从编辑器中删除了 rowHeights 的计算,将 rowHeight 的计算添加到了 Renderer )。
http://blog.botunge.dk/post/2009/10/09/JTable-multiline-cell-renderer.aspx上的建议非常适合使它更漂亮(例如为表格添加颜色和字体)。
总而言之,这个解决方案使用多行呈现 JTable 单元格。当输入或删除文本时,编辑器会自动更新行高。行高的计算留给TextArea 的preferredSize。
第一步:CellRenderer
public class MultiLineCellRenderer extends JTextArea implements
TableCellRenderer {
public MultiLineCellRenderer() {
setEditable(false);
setLineWrap(true);
setWrapStyleWord(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof String) {
setText((String) value);
// We set the width and force textarea to recompute the preferred height
setSize(table.getColumnModel().getColumn(column).getWidth(), 1000);
// we should not do the following in this method.
// it seems to create an endless loop
// int rowHeight = table.getRowHeight(row);
// int cellHeight = getPreferredSize().height;
// if (cellHeight > rowHeight)
// table.setRowHeight(row, cellHeight);
} else
setText("");
return this;
}
/*
* Make sure to call this method, whenever the table changes.
* Call it from appropriate TableCellRenderer, TableModelListener,
* ComponentListener, TableColumnModelListener.
*/
public void updateRowHeights() {
for (int row = 0; row < table.getRowCount(); row++) {
int rowHeight = 0;
for (int col = 0; col < table.getColumnCount(); col++) {
Object value = table.getValueAt(row, col);
if (value != null)
setText(value.toString());
else
setText("");
setSize(table.getColumnModel().getColumn(col).getWidth(), 1000);
int cellHeight = getPreferredSize().height;
if (cellHeight > rowHeight)
rowHeight = cellHeight;
}
table.setRowHeight(row, rowHeight);
}
}
}
第 2 步:CellEditor(我假设可能有一个更短的解决方案,而不覆盖 JTextArea)。
public class MultiLineCellEditor extends AbstractCellEditor implements
TableCellEditor {
MyTextArea textArea;
JTable table;
public MultiLineCellEditor(JTable ta) {
super();
table = ta;
// this component relies on having this renderer for the String
// class
MultiLineCellRenderer renderer = new MultiLineCellRenderer();
table.setDefaultRenderer(String.class, renderer);
textArea = new MyTextArea();
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
}
public Object getCellEditorValue() {
return textArea.getText();
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
textArea.setText(table.getValueAt(row, column).toString());
textArea.rowEditing = row;
textArea.columnEditing = column;
textArea.lastPreferredHeight = textArea.getPreferredSize().height;
return textArea;
}
/**
* This method determines the height in pixel of a cell given the text it
* contains
*/
private int cellHeight(int row, int col) {
if (row == table.getEditingRow() && col == table.getEditingColumn())
return textArea.getPreferredSize().height;
else
return table
.getDefaultRenderer(String.class)
.getTableCellRendererComponent(table,
table.getModel().getValueAt(row, col), false,
false, row, col).getPreferredSize().height;
}
void cellGrewEvent(int row, int column) {
updateRow(row);
}
void cellShrankEvent(int row, int column) {
updateRow(row);
}
void updateRow(int row) {
int maxHeight = 0;
for (int j = 0; j < table.getColumnCount(); j++) {
int ch;
if ((ch = cellHeight(row, j)) > maxHeight) {
maxHeight = ch;
}
}
table.setRowHeight(row, maxHeight);
}
class MyTextArea extends JTextArea implements KeyListener {
private static final long serialVersionUID = 1L;
int lastPreferredHeight = 0;
int rowEditing;
int columnEditing;
MyTextArea() {
addKeyListener(this);
// This is a fix to Bug Id 4256006
addAncestorListener(new AncestorListener() {
public void ancestorAdded(AncestorEvent e) {
requestFocus();
}
public void ancestorMoved(AncestorEvent e) {
}
public void ancestorRemoved(AncestorEvent e) {
}
});
}
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
if (getPreferredSize().getHeight() > lastPreferredHeight) {
lastPreferredHeight = getPreferredSize().height;
cellGrewEvent(rowEditing, columnEditing);
// this will trigger the addition of extra lines upon the
// cell growing and prevent all the text being lost when
// the cell grows to the point of requiring scrollbars
table.setValueAt(getText(), rowEditing, columnEditing);
} else if (getPreferredSize().getHeight() < lastPreferredHeight) {
lastPreferredHeight = getPreferredSize().height;
cellShrankEvent(rowEditing, columnEditing);
} else if (table.getValueAt(rowEditing, columnEditing).equals(""))
table.setValueAt(getText(), rowEditing, columnEditing);
}
}
}
这里有一些测试它的代码。
public class MultiLineCellExample extends JFrame {
private static final long serialVersionUID = 1L;
public MultiLineCellExample() {
DefaultTableModel dm = new DefaultTableModel() {
private static final long serialVersionUID = 1L;
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
};
dm.setDataVector(
new Object[][] {
{ "aa TEST TEST TEST TEST TEST TEST TEST TEST END",
"bb", "cc" }, { "A\nA", "B\nB", "C\nC" } },
new Object[] { "1", "2", "3" });
JTable table = new JTable(dm);
MultiLineCellEditor editor = new MultiLineCellEditor(table);
table.setDefaultEditor(String.class, editor);
dm.fireTableRowsInserted(0, 0);
JScrollPane scroll = new JScrollPane(table);
getContentPane().add(scroll);
}
public static void main(String[] args) {
MultiLineCellExample mlce = new MultiLineCellExample();
mlce.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mlce.setSize(400, 400);
mlce.pack();
mlce.setVisible(true);
}
}