我有一个带有自定义单元格渲染器的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();
}
答案 0 :(得分:2)
奇怪的是,行为不是确定性的。
这种行为总是让我怀疑incorrect synchronization。
目前尚不清楚TableCellRenderer
的工作原理,但您可以尝试HTML,许多Swing组件都支持此功能。
另一个有用的练习是准备一个sscce,用于在微型中重现问题。一个小而完整的例子可能会暴露这个问题。它还允许其他人在不同平台上测试您的方法。
答案 1 :(得分:2)
我相信你遇到的问题与我提出这个问题时的问题相同:
我找到了解决问题的方法,我相信它也可以帮到你 答案在这里: 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的这个问题的原因)。
这样,表的剪切就像它应该的那样完成,每页只打印完整的行,如果需要,每行都会在几页上将行分开。