如何在 jtable 单元格中换行?

新手上路,请多包涵

我正在尝试实现 本教程 中所述的自定义 TableRenderer。我想让渲染器对给定单元格的每个文本进行换行。这个想法是,使用 TextArea 作为渲染器,因为它支持换行。但是,以下代码的行为并不像预期的那样:

 public class LineWrapCellRenderer  extends JTextArea implements TableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(
            JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column) {
        this.setText((String)value);
        this.setWrapStyleWord(true);
        this.setLineWrap(true);
        return this;
    }

}

我设置这个渲染器

table.setDefaultRenderer(String.class, new LineWrapCellRenderer());

但是单元格条目保持未包装状态。如果我将 this.setBackground(Color.YELLOW) 添加到 getTableCellRendererComponent() 方法,所有单元格都按预期显示为黄色,但未包裹。

有任何想法吗?

更新: 正如 Michael Borgwardt 在评论中所说,问题不是换行,而是行高:JTables 行的大小是固定的,所以如果单元格越来越高(因为文本现在是多行的),我们必须增加行高。但是多少钱?我会检查这是否值得另一个 SO 问题。如果没有,我将在此处添加此解决方案。

Update2: 以下代码将确定行高(如果放在 getTableCellRendererComponent() ):

 int fontHeight = this.getFontMetrics(this.getFont()).getHeight();
int textLength = this.getText().length();
int lines = textLength / this.getColumns() +1;//+1, cause we need at least 1 row.
int height = fontHeight * lines;
table.setRowHeight(row, height);

原文由 Arvodan 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.5k
2 个回答

问题是 JTable 中行的高度是固定的,所以这不仅仅是一个包装渲染器的问题;我不确定为什么没有,但如果有,换行的文本将被裁剪——或者这可能正是您所看到的。要调整行高,您需要单独设置它们。

这是一些代码

 int rows = 10;
int cols = 5;
JTable table = new JTable(rows, cols);

// Set the 1st row to 60 pixels high
table.setRowHeight(0, 60);

// Set the height of all rows to 32 pixels high,
// regardless if any heights were assigned to particular rows
table.setRowHeight(32);
// the height of the 1st row is set to 32 pixels high

// Returns the preferred height of a row.
// The result is equal to the tallest cell in the row.
public int getPreferredRowHeight(JTable table, int rowIndex, int margin) {
    // Get the current default height for all rows
    int height = table.getRowHeight();

    // Determine highest cell in the row
    for (int c=0; c<table.getColumnCount(); c++) {
        TableCellRenderer renderer = table.getCellRenderer(rowIndex, c);
        Component comp = table.prepareRenderer(renderer, rowIndex, c);
        int h = comp.getPreferredSize().height + 2*margin;
        height = Math.max(height, h);
    }
    return height;
}

// The height of each row is set to the preferred height of the
// tallest cell in that row.
public void packRows(JTable table, int margin) {
    packRows(table, 0, table.getRowCount(), margin);
}

// For each row >= start and < end, the height of a
// row is set to the preferred height of the tallest cell
// in that row.
public void packRows(JTable table, int start, int end, int margin) {
    for (int r=0; r<table.getRowCount(); r++) {
        // Get the preferred height
        int h = getPreferredRowHeight(table, r, margin);

        // Now set the row height using the preferred height
        if (table.getRowHeight(r) != h) {
            table.setRowHeight(r, h);
        }
    }
}

原文由 Michael Borgwardt 发布,翻译遵循 CC BY-SA 4.0 许可协议

您好,我遇到了同样的问题,但我实施的解决方案的灵感来自 Java 教程中用于绘制多行文本并使用文本 API 在单元格上绘制文本的示例。

http://java.sun.com/docs/books/tutorial/2d/text/drawmulstring.html

 import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.BreakIterator;

import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;

public class MultilineTableCell
    implements TableCellRenderer {
    class CellArea extends DefaultTableCellRenderer {
        /**
         *
         */
        private static final long serialVersionUID = 1L;
        private String text;
        protected int rowIndex;
        protected int columnIndex;
        protected JTable table;
        protected Font font;
        private int paragraphStart,paragraphEnd;
        private LineBreakMeasurer lineMeasurer;

        public CellArea(String s, JTable tab, int row, int column,boolean isSelected) {
            text = s;
            rowIndex = row;
            columnIndex = column;
            table = tab;
            font = table.getFont();
            if (isSelected) {
                setForeground(table.getSelectionForeground());
                setBackground(table.getSelectionBackground());
            }
        }
        public void paintComponent(Graphics gr) {
            super.paintComponent(gr);
            if ( text != null && !text.isEmpty() ) {
                Graphics2D g = (Graphics2D) gr;
                if (lineMeasurer == null) {
                    AttributedCharacterIterator paragraph = new AttributedString(text).getIterator();
                    paragraphStart = paragraph.getBeginIndex();
                    paragraphEnd = paragraph.getEndIndex();
                    FontRenderContext frc = g.getFontRenderContext();
                    lineMeasurer = new LineBreakMeasurer(paragraph,BreakIterator.getWordInstance(), frc);
                }
                float breakWidth = (float)table.getColumnModel().getColumn(columnIndex).getWidth();
                float drawPosY = 0;
                // Set position to the index of the first character in the paragraph.
                lineMeasurer.setPosition(paragraphStart);
                // Get lines until the entire paragraph has been displayed.
                while (lineMeasurer.getPosition() < paragraphEnd) {
                    // Retrieve next layout. A cleverer program would also cache
                    // these layouts until the component is re-sized.
                    TextLayout layout = lineMeasurer.nextLayout(breakWidth);
                    // Compute pen x position. If the paragraph is right-to-left we
                    // will align the TextLayouts to the right edge of the panel.
                    // Note: this won't occur for the English text in this sample.
                    // Note: drawPosX is always where the LEFT of the text is placed.
                    float drawPosX = layout.isLeftToRight()
                        ? 0 : breakWidth - layout.getAdvance();
                    // Move y-coordinate by the ascent of the layout.
                    drawPosY += layout.getAscent();
                    // Draw the TextLayout at (drawPosX, drawPosY).
                    layout.draw(g, drawPosX, drawPosY);
                    // Move y-coordinate in preparation for next layout.
                    drawPosY += layout.getDescent() + layout.getLeading();
                }
                table.setRowHeight(rowIndex,(int) drawPosY);
            }
        }
    }
    public Component getTableCellRendererComponent(
            JTable table, Object value,boolean isSelected, boolean hasFocus, int row,int column
        )
    {
        CellArea area = new CellArea(value.toString(),table,row,column,isSelected);
        return area;
    }
}

它也调整行高的大小,但只有当此渲染器用于单个列时它才能很好地完成。

这就是我用来调用它来呈现我的表格的方式。

 final int wordWrapColumnIndex = ...;
myTable = new JTable() {
    public TableCellRenderer getCellRenderer(int row, int column) {
        if (column == wordWrapColumnIndex ) {
            return wordWrapRenderer;
        }
        else {
            return super.getCellRenderer(row, column);
        }
    }
};

原文由 Alessandro Rossi 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题