如何在用户输入时调整JTable行的高度?

时间:2012-01-23 16:49:56

标签: java swing resize jtable tablecelleditor

我有一个可编辑的JTable。当用户输入时,如果文本比宽度长,我需要增加高度。我已将linewrap设置为true,但它仅在用户按Enter后更改高度。我错过了什么?我已经查看了解决调整大小问题的答案(例如cellRenderer中的this,但我需要在用户输入时调整高度,而不是在完成输入后调整高度。

public class EndCycleCellEditor extends AbstractCellEditor implements TableCellEditor, KeyListener  {
    JComponent component;

    private ArrayList<ArrayList<Integer>> rowColHeight = new ArrayList<ArrayList<Integer>>();

    public EndCycleCellEditor(){
        component  = new JTextArea();
        ((JTextArea) component).setWrapStyleWord(true);
        ((JTextArea) component).setLineWrap(true);
        component.addKeyListener(this);
    }

    @Override
    public Object getCellEditorValue() {
        return ((JTextArea) component).getText();
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected, int row, int column) {
        ((JTextArea)component).setText(value.toString());
        return component;
    }

    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void keyPressed(KeyEvent e) {
        // TODO Auto-generated method stub

            }

    @Override
    public void keyReleased(KeyEvent e) {
        if(((JTextArea) component).getText().length() >= 200){
            Toolkit.getDefaultToolkit().beep();
            ((JTextArea)component).setText(((JTextArea)component).getText().substring(0,200) );
        }

    }



}

2 个答案:

答案 0 :(得分:4)

1)这种方式调整大小是可能的,但丑陋而不是user_friendly

2)不要使用非标准黑客作为JTable中的MultiLines跨度

3)将JTextArea添加到JScrollPane,但是您必须覆盖另一个JScrollPane内的滚动JScrollPane

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

class JTableMultiLineSupport extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

    private static final long serialVersionUID = 1L;
    private JTextArea editor = new JTextArea(4, 10);
    private JScrollPane jsp = new JScrollPane(editor);
    private JTable table;
    private int row;
    private int col;
    private JTextArea renderer = new JTextArea(4, 10);

    public static void main(String[] args) {
        JTable table = new JTable(new String[][]{
                    {"1\n2\n3\n4\n5\n6\n7", "1\n2\n3\n4\n5\n6\n7", "1\n2\n3\n4\n5\n6\n7"},
                    {"1\n2\n3\n4\n5\n6\n7", "1\n2\n3\n4\n5\n6\n7", "1\n2\n3\n4\n5\n6\n7"}},
                new String[]{"First Column", "Second Column", "Third Column"});
        JTableMultiLineSupport mls = new JTableMultiLineSupport();
        table.setDefaultEditor(Object.class, mls);
        table.setDefaultRenderer(Object.class, mls);
        table.setRowHeight(0, 30);
        table.setRowHeight(1, 70);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JFrame frame = new JFrame("Test");
        frame.add(new JScrollPane(table));
        frame.pack();
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected, int row, int col) {
        this.table = table;
        this.row = row;
        this.col = col;
        editor.setText(value.toString());
        return jsp;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        renderer.setText(value == null ? "" : value.toString());
        renderer.setEnabled(false);
        return renderer;
    }

    @Override
    public Object getCellEditorValue() {
        return editor.getText();
    }

    @Override
    public boolean stopCellEditing() {
        table.getModel().setValueAt(editor.getText(), row, col);
        return true;
    }
}

答案 1 :(得分:0)

[编辑:我的初步答案有一些错误和影响。同时,我根据各种例子找到了一个更优雅的解决方案。]

此解决方案基于http://www.coderanch.com/t/336033/GUI/java/MultiLine-JTable - 但我做了一些错误修正(主要是:从编辑器中删除了rowHeights的计算,将rowHeight的计算添加到渲染器中)。

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);
}

}