具有多行单元格渲染器的JTable打印非常奇怪

时间:2011-05-14 16:02:46

标签: java swing printing jtable

我有一个带有自定义单元格渲染器的JTable,用于多行单元格。一切都还可以,JTable在屏幕上画得很好,我很高兴,但是当我试图简单地打印它时,我想出了一个非常奇怪的问题。使用:

table.print(PrintMode.FIT_WIDTH,new MessageFormat(“...”),new MessageFormat(“...”));

我看到桌子没有完全打印。然后使用同事制作的另一个类来打印JTables,我得到了相同的结果:

表格(包含多行单元格)需要22页才能打印。打印文档(我只用xps格式查看,因为我没有打印机)也有22页。但是直到第16页,所有内容都按预期打印,之后只打印了表格的边框和列标题。

奇怪(对我而言)当我尝试使用另一个不允许多行单元格的单元格渲染器打印表格时,表格需要16页并完全打印,尽管在冗长的单元格值中进行裁剪。

我在网上搜索但我没有运气。有人知道为什么会这样吗?有解决方案吗?

更新

我的细胞渲染器如下:

public class MultiLineTableCellRenderer extends JTextPane implements TableCellRenderer {
private List<List<Integer>> rowColHeight = new ArrayList<List<Integer>>();

public MultiLineTableCellRenderer() {
    setOpaque(true);
}

public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected, boolean hasFocus,
        int row, int column) {
    String s = (String)value;
    if (s.equals("<περιοδάριθμος>")) {
        setForeground(Color.blue);
    }
    else if(s.equals("<παραγραφάριθμος>")) {
        setForeground(Color.red);
    }
    else {
        setForeground(Color.black);
    }
    setBackground(new Color(224, 255, 255));
    if (isSelected) {
         setBackground(Color.GREEN);
    }
    setFont(table.getFont());
    setFont(new Font("Tahoma", Font.PLAIN, 10));
    if (hasFocus) {
        setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
        if (table.isCellEditable(row, column)) {
            setForeground(UIManager.getColor("Table.focusCellForeground"));
            setBackground(UIManager.getColor("Table.focusCellBackground"));
        }
    } else {
        setBorder(new EmptyBorder(1, 2, 1, 2));
    }
    if (value != null) {
        setText(value.toString());
    } else {
        setText("");
    }
    adjustRowHeight(table, row, column);

    SimpleAttributeSet bSet = new SimpleAttributeSet();
    StyleConstants.setAlignment(bSet, StyleConstants.ALIGN_CENTER);
    StyleConstants.setFontFamily(bSet, "Tahoma");
    StyleConstants.setFontSize(bSet, 11);
    StyledDocument doc = getStyledDocument();
    doc.setParagraphAttributes(0, 100, bSet, true);
    return this;
}

private void adjustRowHeight(JTable table, int row, int column) {
    int cWidth = table.getTableHeader().getColumnModel().getColumn(column).getWidth();
    setSize(new Dimension(cWidth, 1000));
    int prefH = getPreferredSize().height;
    while (rowColHeight.size() <= row) {
        rowColHeight.add(new ArrayList<Integer>(column));
    }
    List<Integer> colHeights = rowColHeight.get(row);
    while (colHeights.size() <= column) {
        colHeights.add(0);
    }
    colHeights.set(column, prefH);
    int maxH = prefH;
    for (Integer colHeight : colHeights) {
        if (colHeight > maxH) {
            maxH = colHeight;
        }
    }
    if (table.getRowHeight(row) != maxH) {
        table.setRowHeight(row, maxH);
    }
}

}

此外,如果您测试以下非常简单的示例,您会发现打印出现严重错误,但我真的找不到它!

public static void main(String[] args) throws PrinterException {
  DefaultTableModel model = new DefaultTableModel();
  model.addColumn("col1");
  model.addColumn("col2");
  model.addColumn("col3");
  int i = 0;
  for (i = 1; i <= 400; i++) {
     String a = "" + i;
     model.addRow(new Object[]{a, "2", "3"});
  }
  JTable tab = new JTable(model);
  tab.print();
}

3 个答案:

答案 0 :(得分:2)

  

奇怪的是,行为不是确定性的。

这种行为总是让我怀疑incorrect synchronization

目前尚不清楚TableCellRenderer的工作原理,但您可以尝试HTML,许多Swing组件都支持此功能。

另一个有用的练习是准备一个sscce,用于在微型中重现问题。一个小而完整的例子可能会暴露这个问题。它还允许其他人在不同平台上测试您的方法。

答案 1 :(得分:2)

我相信你遇到的问题与我提出这个问题时的问题相同:

Truncated JTable print output

我找到了解决问题的方法,我相信它也可以帮到你 答案在这里: Truncated JTable print output

总结我的答案:

如果您的TableCellRenderer是您的代码中唯一将行设置为正确高度的地方,那么您将遇到由JTable内部优化引起的问题:JTable仅调用TableCellRenderers用于已经(或者是即将展示。

如果并非所有单元格都显示在屏幕上,则不会调用所有渲染器,因此并非所有行都设置为所需的高度。如果您的行不是正确的高度,则您的JTable总高度不正确。毕竟,确定整体JTable高度的一部分是考虑每个表行的高度。如果JTable总高度不正确,则会导致打印截断,因为JTable总高度是打印布局逻辑中考虑的参数。

解决此问题的一种简单(但可能不是吱吱作响的干净)方法是在打印之前手动访问所有单元格渲染器。有关执行此操作的示例,请参阅我的链接答案。我实际上选择在用数据填充表格后立即进行渲染器访问,因为这修复了JTable滚动条范围的一些错误行为(除了修复打印。)

即使打印被破坏,表在屏幕上显示和工作正常的原因是因为当您在表格中滚动时,随着新单元格出现在屏幕上,并且渲染器设置适当的行高度,将调用各种渲染器对于新显示的行,然后在运行中重新计算各种维度,当您与表交互时,一切都正常。 (虽然您可能会注意到滚动条“extent”在滚动时会发生变化,但通常不应该这样做。)

答案 2 :(得分:2)

对于提出这个问题的人来说,这个答案可能为时已晚,但对于遇到类似问题的每个人来说,这是我的解决方案;

我有完全相同的问题,我有自己的TableCellRenderer来处理多行字符串,它可以完美地显示表格但是使表格的打印不可靠。 我的解决方案由两部分组成;

第1部分:我已经在getValueAt()中创建了自己的TableModel,我已经复制了#39;作为StringCellRenderer逻辑的一部分,我重新计算并设置表行的高度,以防多行字符串并将字符串作为HTML返回,并使用&#39; break&#39;而不是行分隔符。

第2部分:在调用table.print()之前,我为所有单元格调用getValueAt()(在调用getValueAt()的行上使用内部for循环的列进行for循环),这必须是完成&#39;手动&#39;因为打印功能没有调用所有getValueAt(我在不同论坛上找到了关于执行TableCellRenderers的这个问题的原因)。

这样,表的剪切就像它应该的那样完成,每页只打印完整的行,如果需要,每行都会在几页上将行分开。