How to set the RowHeight dynamically in a JTable

后端 未结 5 1438
感动是毒
感动是毒 2020-12-09 20:39

I want to put a String in a JTable that is longer than the given cell-width. How can I set the rowHeight dynamically so that I can read the whole S

5条回答
  •  忘掉有多难
    2020-12-09 21:10

    Actually JTextArea already implements all the features required to dynamically change its height based on its width. One can see this functionality in action, when JTextArea is used inside a ScrollPane, where its height is automatically adjusted to fit the width of the ScrollPane. To use this feature, one has to first set the size of the JTextArea to some width and then JTextArea#getPreferredSize() will return the required height to display the text (if line wrap is set to true).

    So to dynamically change the row height of a JTable based on its width, one can do the following:

    1. Add a custom TableCellRenderer to the table that returns a JTextArea in TableCellRenderer#getTableCellRendererComponent()
    2. Listen to the resizing of the columns as explained here: Java JTable detect Column re-sized by user
    3. Update the row heights of the columns as explained here: Auto adjust the height of rows in a JTable
    4. During the update of the row heights, one calculates the required size of the JTextArea by first setting the new width and then getting the preferred height as shown in the following code snippet

    Update function of the row heights:

    public static void updateRowHeights(int column, int width, JTable table){
        for (int row = 0; row < table.getRowCount(); row++) {
            int rowHeight = table.getRowHeight();
            Component comp = table.prepareRenderer(table.getCellRenderer(row, column), row, column);
            Dimension d = comp.getPreferredSize();
                // first set the size to the new width
            comp.setSize(new Dimension(width, d.height));
                // then get the preferred size
            d = comp.getPreferredSize();
            rowHeight = Math.max(rowHeight, d.height);
                // finally set the height of the table
            table.setRowHeight(row, rowHeight);
        }
    }
    

    With this approach, no further calculations of colums or rows are necessary.

    Here is the complete code of the OP's ExampleTable, adjusted to this implementation.

    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.JTextArea;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.event.TableColumnModelEvent;
    import javax.swing.event.TableColumnModelListener;
    import javax.swing.table.AbstractTableModel;
    import javax.swing.table.JTableHeader;
    import javax.swing.table.TableCellRenderer;
    import javax.swing.table.TableColumn;
    
    public class ExampleTable {
    
        public class RowHeightCellRenderer extends JTextArea implements TableCellRenderer {
    
            public Component getTableCellRendererComponent(
                    JTable table, Object value,
                    boolean isSelected, boolean hasFocus,
                    int row, int column) {
    
                setEditable(false);
                setLineWrap(true);
                setWrapStyleWord(true);
    
                if (isSelected) {
                    setBackground(table.getSelectionBackground());
                    setForeground(table.getSelectionForeground());
                } else {
                    setBackground(table.getBackground());
                    setForeground(table.getForeground());
                }
    
                setText(value.toString());
                return this;
            }
        }
    
        public static void updateRowHeights(int column, int width, JTable table){
            for (int row = 0; row < table.getRowCount(); row++) {
                int rowHeight = table.getRowHeight();
                Component comp = table.prepareRenderer(table.getCellRenderer(row, column), row, column);
                Dimension d = comp.getPreferredSize();
                comp.setSize(new Dimension(width, d.height));
                d = comp.getPreferredSize();
                rowHeight = Math.max(rowHeight, d.height);
                table.setRowHeight(row, rowHeight);
            }
        }
    
        public JPanel createTable() {
    
            JPanel totalGUI = new JPanel();
    
            //define titles for table
            final String[] columnNames = {"TITLE1", "TITLE2", "TITLE3"};
    
            //table data
            final Object[][] rowData = {       
                    {new Integer(34), "Steve", "test test test"},
                    {new Integer(32), "Patrick", "dumdi dumdi dummdi dumm di di didumm"},
                    {new Integer(10), "Sarah", "blabla bla bla blabla bla bla blabla"},};
    
            AbstractTableModel model = new AbstractTableModel() {
                @Override
                public Class getColumnClass(int columnIndex) {
                    return String.class;
                }
    
                public String getColumnName(int column) { return columnNames[column].toString(); }
                public int getRowCount() { return rowData.length; }
                public int getColumnCount() { return columnNames.length; }
                public Object getValueAt(int row, int col) { return rowData[row][col]; }
                public boolean isCellEditable(int row, int column) { return true; }
                public void setValueAt(Object value, int row, int col) {
                    rowData[row][col] = value;
                    fireTableCellUpdated(row, col);
                }
            };
    
            //create object 'textTable'
            final JTable textTable = new JTable();
    
            textTable.setDefaultRenderer(String.class, new RowHeightCellRenderer());
            textTable.setModel(model);
    
            //set column width
            textTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 
            textTable.getColumnModel().getColumn(0).setPreferredWidth(60);
            textTable.getColumnModel().getColumn(1).setPreferredWidth(60);
    
            ColumnListener cl = new ColumnListener(){
    
                @Override
                public void columnMoved(int oldLocation, int newLocation) {
                }
    
                @Override
                public void columnResized(int column, int newWidth) {
                    updateRowHeights(column, newWidth, textTable);
                }
    
            };
    
            textTable.getColumnModel().addColumnModelListener(cl);
            textTable.getTableHeader().addMouseListener(cl);
    
            // initial update of row heights
            TableColumn c = textTable.getColumnModel().getColumn(2);
            updateRowHeights(2, c.getWidth(), textTable);
    
            //scrollbar
            JScrollPane scrollPane = new JScrollPane(textTable);
    
            totalGUI.add(scrollPane);               
            return totalGUI;
        }
    
        private static void createAndShowGUI() {
    
            //create main frame
            JFrame mainFrame = new JFrame("");
            mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            ExampleTable test = new ExampleTable();
    
            JPanel totalGUI = new JPanel();
            totalGUI = test.createTable();
    
            //visible mode
            mainFrame.add(totalGUI); //integrate main panel to main frame
            mainFrame.pack();
            mainFrame.setVisible(true);     
        }
    
    
        public static void main (String[] args) {               
    
            createAndShowGUI();     
    
        }//main
    
    
        abstract class ColumnListener extends MouseAdapter implements TableColumnModelListener {
    
            private int oldIndex = -1;
            private int newIndex = -1;
            private boolean dragging = false;
    
            private boolean resizing = false;
            private int resizingColumn = -1;
            private int oldWidth = -1;
    
            @Override
            public void mousePressed(MouseEvent e) {
                // capture start of resize
                if(e.getSource() instanceof JTableHeader) {
                    JTableHeader header = (JTableHeader)e.getSource();
                    TableColumn tc = header.getResizingColumn();
                    if(tc != null) {
                        resizing = true;
                        JTable table = header.getTable();
                        resizingColumn = table.convertColumnIndexToView( tc.getModelIndex());
                        oldWidth = tc.getPreferredWidth();
                    } else {
                        resizingColumn = -1;
                        oldWidth = -1;
                    }
                }   
            }
    
            @Override
            public void mouseReleased(MouseEvent e) {
                // column moved
                if(dragging && oldIndex != newIndex) {
                    columnMoved(oldIndex, newIndex);
                }
                dragging = false;
                oldIndex = -1;
                newIndex = -1;
    
                // column resized
                if(resizing) {
                    if(e.getSource() instanceof JTableHeader) {
                        JTableHeader header = (JTableHeader)e.getSource();
                        TableColumn tc = header.getColumnModel().getColumn(resizingColumn);
                        if(tc != null) {
                            int newWidth = tc.getPreferredWidth();
                            if(newWidth != oldWidth) {
                                columnResized(resizingColumn, newWidth);
                            }
                        }
                    }   
                }
                resizing = false;
                resizingColumn = -1;
                oldWidth = -1;
            }
    
            @Override
            public void columnAdded(TableColumnModelEvent e) {      
            }
    
            @Override
            public void columnRemoved(TableColumnModelEvent e) {        
            }
    
            @Override
            public void columnMoved(TableColumnModelEvent e) {
                // capture dragging
                dragging = true;
                if(oldIndex == -1){
                    oldIndex = e.getFromIndex();
                }
    
                newIndex = e.getToIndex();  
            }
    
            @Override
            public void columnMarginChanged(ChangeEvent e) {
            }
    
            @Override
            public void columnSelectionChanged(ListSelectionEvent e) {
            }
    
            public abstract void columnMoved(int oldLocation, int newLocation);
            public abstract void columnResized(int column, int newWidth);
        }
    }
    

    Note, that I reused and changed some of the code from Java JTable detect Column re-sized by user and Auto adjust the height of rows in a JTable.

提交回复
热议问题