【问题标题】:How do I resize the height of a JTable row as the user types?如何在用户键入时调整 JTable 行的高度?
【发布时间】:2013-03-09 09:01:02
【问题描述】:

我有一个可编辑的 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) );
        }

    }



}

【问题讨论】:

    标签: java swing resize jtable tablecelleditor


    【解决方案1】:

    1) 以这种方式调整大小是可能的,但丑陋且不友好

    2) 不要使用 non_standard hack 作为 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;
        }
    }
    

    【讨论】:

    • 对不起,解决办法是什么?
    • 有什么方法可以在你输入时丢失滚动窗格并使行增加它们的高度???
    【解决方案2】:

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

    此解决方案基于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);
    }
    
    }
    

    【讨论】:

    • 示例不可编译。
    猜你喜欢
    • 2015-07-15
    • 1970-01-01
    • 2010-12-19
    • 2015-03-27
    • 2010-11-27
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 2016-12-12
    相关资源
    最近更新 更多