如何在JTable中动态设置RowHeight

Ram*_*ses 8 java swing jtable

我想把一个字符串放在JTable比给定单元格宽度更长的字符串中.如何rowHeight动态设置以便我可以读取整个String?这是一个例子:

import javax.swing.*;

public class ExampleTable {

public JPanel createTable() {               
    JPanel totalGUI = new JPanel();

    //define titles for table
    String[] title = {"TITLE1", "TITLE2", "TITLE3"};

    //table data
    Object[][] playerdata = {       
    {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"},};

    //create object 'textTable'
    JTable textTable = new JTable(playerdata,title);

    //set column width
    textTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 
    textTable.getColumnModel().getColumn(0).setPreferredWidth(60);
    textTable.getColumnModel().getColumn(1).setPreferredWidth(60);
    textTable.setDefaultRenderer(String.class, new RowHeightCellRenderer());

    //scrollbar
    JScrollPane scrollPane = new JScrollPane(textTable);

    totalGUI.add(scrollPane);               
    return totalGUI;
}

private static void createAndShowGUI() {

    //create main frame
    JFrame mainFrame = new JFrame("");
    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
}
Run Code Online (Sandbox Code Playgroud)

在这里,您将看到对每个给定单元格的文本进行换行的代码

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


    public class RowHeightCellRenderer extends JTextArea implements TableCellRenderer
    {
      /**
         * 
         */
        private static final long serialVersionUID = 1L;

    public Component getTableCellRendererComponent (JTable table, 
                                                    Object value, 
                                                    boolean isSelected, 
                                                    boolean hasFocus, 
                                                    int row, 
                                                    int column )  {
        setText( value.toString() );    
        return this;
      }
    }
Run Code Online (Sandbox Code Playgroud)

谢谢,但我想动态实现RowHeight,具体取决于字符串长度...我想读取单元格中的整个字符串/文本.有什么建议?

我是java初学者,这是我的第一个问题.我很高兴得到答案.

kle*_*tra 13

使用JTextArea作为渲染组件时会出现几个问题(如果不是所有这些都已在本网站的几个QA中进行了解释).试着总结一下:

将单个行高调整为渲染组件的大小要求

基本上,要走的路是根据需要循环遍历单元格

  • 使用数据配置其渲染器
  • 询问渲染组件的首选大小
  • 将表行高度设置为pref高度

OP编辑过的问题中的updateRowHeight方法很好.

JTextArea计算其preferredSize

为了获得一个合理的尺寸提示,它需要在另一个维度上以一些合理的尺寸"播种".也就是说,如果我们想要一个需要宽度的高度,那么必须在每个调用中完成.在表的上下文中,合理的宽度是当前列宽:

public Component getTableCellRendererComponent(JTable table,
        Object value, boolean isSelected, boolean hasFocus, int row,
        int column) {
    ... // configure visuals
    setText((String) value);
    setSize(table.getColumnModel().getColumn(column).getWidth(),
            Short.MAX_VALUE);
    return this;
}// getTableCellRendererComponent
Run Code Online (Sandbox Code Playgroud)

动态调整高度

行高度完全确定在表/列/模型的某些稳定状态.因此,在初始化完成后以及任何其所依赖的状态发生更改时,您都要设置它(调用updateRowHeight)一次.

// TableModelListener
@Override
public void tableChanged(TableModelEvent e) {
    updateRowHeights();
}

// TableColumnModelListener
@Override
public void columnMarginChanged(ChangeEvent e) {
    updateRowHeights();
}
Run Code Online (Sandbox Code Playgroud)

注意

作为一般规则,getXXRendererComponent中的所有参数都是严格只读的,实现不得更改调用者的任何状态.从渲染器中更新rowHeight是错误的.


The*_*tor 5

许多好的想法与其他答案以及相关问题相关联.

所以这就是我如何修改你的类以获得一个具有完全工作的自动行高的表:

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import java.awt.*;

public class ExampleTable implements TableModelListener {
    JTable textTable;

    public JPanel createTable() {
        JPanel totalGUI = new JPanel();

        //define titles for table
        String[] title = {"TITLE1", "TITLE2", "TITLE3"};

        //table data
        Object[][] playerdata = {
                {new Integer(3), "Steve", "test test test"},
                {new Integer(32), "Patrick", "du hu hu hu hu hu hu hu uh u kkkkkk oooo pppp"},
                {new Integer(10), "Sarah", "xxxxxxxxxxxxx aaaaaaaaaa bbbbbbbbbbbb dddddddddddd xxxxxxx gggewr  eeeeeeeeee22 ddd g fffffff zzzzzzz"},};

        //define tablemodel
        TableModel model = new DefaultTableModel(playerdata, title);

        //create object 'textTable'
        textTable = new JTable(model);

        //set column width
        textTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        textTable.getColumnModel().getColumn(0).setPreferredWidth(17);
        textTable.getColumnModel().getColumn(1).setPreferredWidth(45);
        textTable.getColumnModel().getColumn(2).setPreferredWidth(200);

        //put line breaks if string is longer than cell-width
        RowHeightCellRenderer dynRow = new RowHeightCellRenderer();
        textTable.getColumnModel().getColumn(2).setCellRenderer(dynRow);

        // No more data changes; install listeners
        textTable.getModel().addTableModelListener(this);
        textTable.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
            /**
             * We only need to recalculate once; so track if we are already going to do it.
             */
            boolean columnHeightWillBeCalculated = false;

            @Override
            public void columnAdded(TableColumnModelEvent e) {
            }

            @Override
            public void columnRemoved(TableColumnModelEvent e) {
            }

            @Override
            public void columnMoved(TableColumnModelEvent e) {
            }

            @Override
            public void columnMarginChanged(ChangeEvent e) {
                if (!columnHeightWillBeCalculated && textTable.getTableHeader().getResizingColumn() != null) {
                    columnHeightWillBeCalculated = true;
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            // textTable.getTableHeader().getResizingColumn() is != null as long as the user still is holding the mouse down
                            // To avoid going over all data every few milliseconds wait for user to release
                            if (textTable.getTableHeader().getResizingColumn() != null) {
                                SwingUtilities.invokeLater(this);
                            } else {
                                tableChanged(null);
                                columnHeightWillBeCalculated = false;
                            }
                        }
                    });
                }
            }

            @Override
            public void columnSelectionChanged(ListSelectionEvent e) {
            }
        });

        //scrollbar
        JScrollPane scrollPane = new JScrollPane(textTable);
        totalGUI.add(scrollPane);
        return totalGUI;
    }

    public void tableChanged(TableModelEvent e) {
        final int first;
        final int last;
        if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
            // assume everything changed
            first = 0;
            last = textTable.getModel().getRowCount();
        } else {
            first = e.getFirstRow();
            last = e.getLastRow() + 1;
        }
        // GUI-Changes should be done through the EventDispatchThread which ensures all pending events were processed
        // Also this way nobody will change the text of our RowHeightCellRenderer because a cell is to be rendered
        if(SwingUtilities.isEventDispatchThread()) {
            updateRowHeights(first, last);
        } else {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    updateRowHeights(first, last);
                }
            });
        }
    }

    private void updateRowHeights(final int first, final int last) {
    /*
     * Auto adjust the height of rows in a JTable.
     * The only way to know the row height for sure is to render each cell
     * to determine the rendered height. After your table is populated with
     * data you can do:
     *
     */
        for (int row = first; row < last; row++) {
            int rowHeight = 20;
            for (int column = 0; column < textTable.getColumnCount(); column++) {
                Component comp = textTable.prepareRenderer(textTable.getCellRenderer(row, column), row, column);
                rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
            }
            if(rowHeight != textTable.getRowHeight(row)) {
                textTable.setRowHeight(row, rowHeight);
                System.out.println("neue Zeilenhöhe: "+rowHeight+" bei Zeile: "+row);
            }
        }
    }

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

        //adjust dynamically the Row height of each cell
        test.tableChanged(null);
    }


    public static void main (String[] args) {
        createAndShowGUI();
    }//main
}
Run Code Online (Sandbox Code Playgroud)

重要变化:

  • 只有在JFrame可见之后才计算高度,因为在此之前我们可能没有正确的字体
  • rowHeight仅从event-dispatch-thread(SwingUtilities.isEventDispatchThread()/ SwingUtilities.invokeLater())更改; 否则,RowHeightCellRenderer当我们处于计算高度的中间时,表可能会为我们分配不同的值
  • 初始化rowHeight到20,所以我们可以再次缩小
  • TableColumnModelListener所以我们知道用户何时调整列的大小并缩小或增大rowHeights(如果不希望这样,你可以安全地删除监听器)

此外,现在我只评估更改的行以进行TableModel更改

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

public class RowHeightCellRenderer extends JTextArea implements TableCellRenderer {

    private static final long serialVersionUID = 1L;


    public RowHeightCellRenderer() {
        setLineWrap(true);
        setWrapStyleWord(true);
    }//constructor

    public Component getTableCellRendererComponent (JTable table,
                                                    Object value,
                                                    boolean isSelected,
                                                    boolean hasFocus,
                                                    int row,
                                                    int column ) {
        this.setText((String) value);

        if(isSelected) {
            this.setBackground(table.getSelectionBackground());
            this.setForeground(table.getSelectionForeground());
        } else {
            this.setBackground(table.getBackground());
            this.setForeground(table.getForeground());
        }

        final int columnWidth = table.getColumnModel().getColumn(column).getWidth();
        final int rowHeight = table.getRowHeight(row);
        this.setSize(columnWidth, rowHeight);

        this.validate();
        return this;
    }//getTableCellRendererComponent

    @Override
    public Dimension getPreferredSize() {
        try {
            // Get Rectangle for position after last text-character
            final Rectangle rectangle = this.modelToView(getDocument().getLength());
            if(rectangle != null) {
                return new Dimension(this.getWidth(),
                                     this.getInsets().top + rectangle.y + rectangle.height +
                                                                  this.getInsets().bottom);
            }
        } catch (BadLocationException e) {
            e.printStackTrace();  // TODO: implement catch
        }

        return super.getPreferredSize();
    }
}//RowHeightCellRenderer
Run Code Online (Sandbox Code Playgroud)

变化:

  • setSize()getTableCellRendererComponent()因为否则物体不能正确地包裹
  • preferedSize根据最后一个字符的位置计算