Please tell me, how to make a JTable column to contain JTextAreas, so the cell's height will increase when user types a lot of text and we can see more than one line (cell gets expanded; as result, row will expand too)
Asked
Active
Viewed 2,231 times
2
-
2It's possible, but why not have a separate JPanel or JDialog with JTextArea/JTextPane which will correspond to the selected table cell? – Joop Eggen Apr 24 '12 at 21:23
-
1When I tried this I got stick facing JTable.set/get row height. http://docs.oracle.com/javase/7/docs/api/javax/swing/JTable.html#setRowHeight(int) Joop you have a way around this??? – ControlAltDel Apr 24 '12 at 21:30
-
1@user1291492 not `Renderer` is for concrete `JTables row`, because J`Table.set/get row height` is valid for all rows in the `JTable` – mKorbel Apr 24 '12 at 21:32
-
1@Jake Badlands whats happens when edited row will be wider than screen, this isn't nice idea, my view – mKorbel Apr 24 '12 at 21:34
-
1You can also opt for a variable row height per row, but this is inefficient, so JTable normally uses fixed row heights. But I meant an other user interface with clicking on a cell getting a text area elsewhere (dialog or panel). See http://www.javareference.com/jrexamples/viewexample.jsp?id=87 for varying the row height. – Joop Eggen Apr 24 '12 at 22:14
-
1@JoopEggen offers a good suggestion; [`TablePopupEditor`](http://stackoverflow.com/a/3591230/230513) is an example. – trashgod Apr 24 '12 at 23:37
2 Answers
5
You need to write your own cell renderer and editor based on JTextArea:
public class Start
{
public static class JTextPaneCellEditor extends AbstractCellEditor implements TableCellEditor, KeyListener
{
private JViewport viewport;
private JTable table;
private int row;
private JTextPane pane;
public JTextPaneCellEditor(){
viewport = new JViewport();
pane = new JTextPane();
viewport.add(pane);
pane.addKeyListener(this);
}
@Override public Object getCellEditorValue(){
return pane.getText();
}
@Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column){
this.table = table;
this.row = row;
pane.setText(value.toString());
int newHeight = (int)pane.getPreferredSize().getHeight();
if(table.getRowHeight(row) < newHeight){
table.setRowHeight(row, newHeight);
}
return pane;
}
@Override public boolean isCellEditable(EventObject e){
if (e instanceof MouseEvent) {
return ((MouseEvent)e).getClickCount() >= 2;
}
return true;
}
@Override public void keyTyped(KeyEvent e){
table.setRowHeight(row, (int)pane.getPreferredSize().getHeight());
}
@Override public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
stopCellEditing();
}
}
@Override public void keyReleased(KeyEvent e){
}
}
private static class JTextPaneCellRenderer extends JViewport implements TableCellRenderer
{
JTextPane pane;
JTextPaneCellRenderer(){
pane = new JTextPane();
add(pane);
}
@Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
pane.setText(value.toString());
table.setRowHeight(row, (int)pane.getPreferredSize().getHeight());
return this;
}
}
public static void main(String[] args){
JTable table = new JTable(new String[][]{{"String String String String StringString String String String StringString String String String StringString String String String StringString String String String String"}, {"String 2"}}, new String[]{"Column"});
table.setDefaultRenderer(Object.class, new JTextPaneCellRenderer());
table.setDefaultEditor(Object.class, new JTextPaneCellEditor());
JFrame test = new JFrame();
test.add(new JScrollPane(table));
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(300, 300);
test.setLocationRelativeTo(null);
test.setVisible(true);
}
}
EDIT: add viewports for better sizing. But the row is still not expanded on first edit. Does anyone have any ideas?
EDIT2: I agree with the comments. The thing you want is possible, but you need untested, hackish custom implementation. You will be better off if you redesigned your layout to exclude such JTable sorcery.

Jakub Zaverka
- 8,816
- 3
- 32
- 48
-
1@mKorbel I tried both doLayout and validate, but the JTable won't get the row height changed. I guess it doesn't ask the components it gets from renderer about their height. – Jakub Zaverka Apr 24 '12 at 21:54
-
1this idea resize particular row is ****** and I hate this idea and is so far and my another blablabla .... , please search in the posts by ([kleopatra](http://stackoverflow.com/users/203657/kleopatra) or [camickr](http://stackoverflow.com/users/131872/camickr)), because this/these issue was/were solved more than once time, may be I'll post an answer here my idea about whatever in the JScrollPane :-), don't forget that only Document can returns that for JTextComponent – mKorbel Apr 24 '12 at 22:09
-
1@mKorbel It looks ugly to as well, and if there is more elegant solution, I will be happy to be educated. For now, this accomplishes what OP wants. – Jakub Zaverka Apr 24 '12 at 22:20
-
1you have to create the same prepareEditor :-), I leaving that, please ping me with comment, then I'll delete my answer here – mKorbel Apr 24 '12 at 22:25
-
This code is almost working, but I have a problem: when I type a lot of text, it gets expanded only for millisecond, and then reverts back to one-line mode. If I will be quick enough and click "Enter" to finish editing in this moment, it saves the expanded state - but when I click the text field again, it reverts back to one-line mode as well! – Jake Badlands Apr 25 '12 at 05:05
-
1
-
1@mKorbel I tried your solution and it looks more ellegant, but I had a hard time adding variable-height editor to the table without setRowHeight(). – Jakub Zaverka Apr 25 '12 at 10:40
-
@JakeBadlands How did you solve the reverting back to single line problem? – Igor Sep 12 '12 at 11:01
2
@Jakub Zaverka
I'll delete this answer later
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
public class AutoWrapTest {
public JComponent makeUI() {
String[] columnNames = {"TextAreaCellRenderer"};
Object[][] data = {
{"123456789012345678901234567890"},
{"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddx"},
{"----------------------------------------------0"},
{">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>|"},};
TableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
JTable table = new JTable(model) {
private static final long serialVersionUID = 1L;
@Override
public void doLayout() {
TableColumn col = getColumnModel().getColumn(0);
for (int row = 0; row < getRowCount(); row++) {
Component c = prepareRenderer(col.getCellRenderer(), row, 0);
if (c instanceof JTextArea) {
JTextArea a = (JTextArea) c;
int h = getPreferredHeight(a) + getIntercellSpacing().height;
if (getRowHeight(row) != h) {
setRowHeight(row, h);
}
}
}
super.doLayout();
} //http://tips4java.wordpress.com/2008/10/26/text-utilities/
private int getPreferredHeight(JTextComponent c) {
Insets insets = c.getInsets();
View view = c.getUI().getRootView(c).getView(0);
int preferredHeight = (int) view.getPreferredSpan(View.Y_AXIS);
return preferredHeight + insets.top + insets.bottom;
}
};
table.setEnabled(false);
table.setShowGrid(false);
table.setTableHeader(null);
table.getColumnModel().getColumn(0).setCellRenderer(new TextAreaCellRenderer());
JScrollPane sp = new JScrollPane(table);
sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
JPanel p = new JPanel(new BorderLayout());
p.add(sp);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new AutoWrapTest().makeUI());
f.setSize(200, 200);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {
private static final long serialVersionUID = 1L;
private final Color evenColor = new Color(230, 240, 255);
public TextAreaCellRenderer() {
super();
setLineWrap(true);
setWrapStyleWord(true);
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
setBackground((row % 2 == 0) ? evenColor : getBackground());
}
setFont(table.getFont());
setText((value == null) ? "" : value.toString());
return this;
}
}

mKorbel
- 109,525
- 20
- 134
- 319
-
Unfortunately, that does not work - the behavior of the text field is the same as before. – Jake Badlands Apr 25 '12 at 04:51