我的自定义 JTable 和自定义 TableRenderer 遇到了一个神秘的问题。 在 95%-99,99% 的情况下,它可以完美工作,但有时渲染器会停止执行其工作,并将表格的一部分(位于 JScrollPane 内)留空。
问题案例如下:
在所有其他情况下,在稍微调整窗口大小后,表格看起来像这样:
现在两列都有一个关联的 TextAreaCellRenderer,其工作原理如下:
public class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {
private final Color evenColor = new Color(252, 248, 202);
public TextAreaCellRenderer() {
super();
setLineWrap(true);
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
@Override
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
setBackground((row % 2 == 0) ? evenColor : getBackground());
}
setWrapStyleWord(true);
setFont(table.getFont());
setText((value == null) ? "" : value.toString());
return this;
}
}
我还必须重写 JTable 的 doLayout 方法,以便能够根据内容计算单元格的高度。自定义表格如下所示:
public class MediaMetaDataTable extends JTable {
@Override
public void doLayout() {
TableColumn col = getColumnModel().getColumn(1);
for (int row = 0; row < getRowCount(); row++) {
Component c = prepareRenderer(col.getCellRenderer(), row, 1);
if (c instanceof JTextArea) {
JTextArea a = (JTextArea) c;
int h = getPreferredHeight(a) + getIntercellSpacing().height;
if (getRowHeight(row) != h) {
setRowHeight(row, h);
}
}
}
super.doLayout();
}
private int getPreferredHeight(final JTextComponent c) {
Insets insets = c.getInsets();
View view = c.getUI().getRootView(c).getView(0);
int preferredHeight = (int) view.getPreferredSpan(View.Y_AXIS);
return preferredHeight + insets.top + insets.bottom;
}
}
该表使用以下参数实例化一次:
metaTable = new MediaMetaDataTable();
metaTable.setModel(new MediaMetaDataTableModel());
metaTable.setEnabled(false);
metaTable.setShowGrid(false);
metaTable.setTableHeader(null);
metaTable.getColumnModel().getColumn(0).setCellRenderer(new TextAreaCellRenderer());
metaTable.getColumnModel().getColumn(1).setCellRenderer(new TextAreaCellRenderer());
metaTable.setPreferredScrollableViewportSize(new Dimension(-1, -1));
metaTable.setShowHorizontalLines(false);
metaTable.setShowVerticalLines(false);
每次数据显示更改时,我都会通过替换底层模型数据来更新表:
List<MediaMetaData> metaInformation = mediaSearchHit.getMetaInformation();
if (metaInformation != null) {
((MediaMetaDataTableModel) metaTable.getModel()).replaceMetaInfos(metaInformation);
}
更新时模型本身会触发表数据更改事件:
public class MediaMetaDataTableModel extends AbstractTableModel {
private List<MediaMetaData> metaInfos = new LinkedList<MediaMetaData>();
public static final int COL_INDEX_NAME = 0;
public static final int COL_INDEX_VALUE = 1;
public void replaceMetaInfos(final List<MediaMetaData> metaInfos) {
this.metaInfos = null;
this.metaInfos = metaInfos;
fireTableDataChanged();
}
...
现在有人知道是什么原因导致了所描述的渲染问题吗?
感谢您的建议。
最佳答案
I also have to override the
doLayout
method of theJTable
to be able to calculate the hight of a cell depending on the content.
要实现此目标,无需重写 doLayout()
方法。我认为最简单的方法是通过使用 BorderLayout
将用于渲染单元格内容的文本区域添加到 JPanel
中,并根据面板的首选大小设置行高。这样,布局管理器将为您完成任务,并且所有单元格的内容都将可见:
@Override
public Component getTableCellRendererComponent(...) {
...
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(this);
table.setRowHeight(row, contentPane.getPreferredSize().height); // sets row's height
return contentPane;
}
正如 @mKorbel 指出的那样,无需使渲染器从 JTextArea
扩展:单个变量即可工作。记住这一点,根据您的工作查看此实现:
class TextAreaRenderer implements TableCellRenderer {
private JTextArea renderer;
private final Color evenColor = new Color(252, 248, 202);
public TextAreaRenderer() {
renderer = new JTextArea();
renderer.setLineWrap(true);
renderer.setWrapStyleWord(true);
renderer.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
renderer.setForeground(table.getSelectionForeground());
renderer.setBackground(table.getSelectionBackground());
} else {
renderer.setForeground(table.getForeground());
renderer.setBackground((row % 2 == 0) ? evenColor : table.getBackground());
}
renderer.setFont(table.getFont());
renderer.setText((value == null) ? "" : value.toString());
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(renderer);
table.setRowHeight(row, contentPane.getPreferredSize().height); // sets row's height
return contentPane;
}
}
屏幕截图
关于java - JTable 渲染有时会停止渲染,但会在调整窗口大小时恢复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20332134/