开发者

JTable with multi-line cell renderer prints very weird

开发者 https://www.devze.com 2023-03-05 17:34 出处:网络
I have a JTable with a custom Cell Renderer for multi-line cells. Everything is ok, the JTable is painted ok in the screen and I am very happy with it, but ast night when I tried to simply print it, I

I have a JTable with a custom Cell Renderer for multi-line cells. Everything is ok, the JTable is painted ok in the screen and I am very happy with it, but ast night when I tried to simply print it, I came up with a very strange issue. Using:

table.print(PrintMode.FIT_WIDTH, new MessageFormat("..."), new MessageFormat("..."));

I saw that the table did not print entirely. Then using another class made from a colleague for printing JTables I had the same result:

The table (with multi-line cells) needed 22 pages to print. The printed document (which I only viewed in xps format since I do not own a printer) had also 22 pages. But up to page 16 everything was printed as expected and after that only the borders and the column headers of the table were printed.

Strangely (to me) enough, when I tried to print the table using another cell renderer that does not allow for multi line cells, the table needed exactly 16 pages and was printed entirely, albeit the cropping in the lengthy cell values.

I searched all over the net but I had no luck. Does anybody know why could this be happening? Is there a solution?

Update:

My cell renderer is the following:

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).getWid开发者_JAVA百科th();
    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);
    }
}

}

Furthermore, if you test the following very simple example you will notice that something is terribly wrong with the printing, but I really can't find what!

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


I believe you are having the same problem that I had when I asked this question:

Truncated JTable print output

I found a solution to my problem, and I believe it may help you as well.
The answer is here: Truncated JTable print output

To summarize my answer:

If your TableCellRenderer is the only place in your code where you are setting rows to their correct height, then you are going to run into trouble caused by an optimization inside JTable: JTable only invokes TableCellRenderers for cells that have been (or are about to be) displayed.

If not all of your cells have been displayed on-screen, then not all of your renderers have been invoked, and so not all of your rows have been set to the desired height. With your rows not being their correct height, your JTable overall height is incorrect. After all, part of determining the overall JTable height is accounting for the height of each of that table's rows. If the JTable overall height isn't correct, this causes the print to truncate, since the JTable overall height is a parameter that is considered in the print layout logic.

An easy (but perhaps not squeaky clean) way to fix this is to visit all of your cell renderers manually before printing. See my linked answer for an example of doing this. I actually chose to do the renderer visitation immediately after populating my table with data, because this fixes some buggy behavior with the JTable's scrollbar extents (in addition to fixing the printing.)

The reason the table looks and works OK on-screen even when printing is broken, is because as you scroll around in the table, the various renderers are invoked as new cells come on screen, and the renderers set the appropriate row height for the newly visible rows, and various dimensions are then are recalculated on the fly, and everything works out OK in the end as you interact with the table. (Although you may notice that the scrollbar "extent" changes as you scroll around, which it really shouldn't normally do.)


Strange thing is that behavior is not deterministic.

Such behavior always makes me suspect incorrect synchronization.

It's not clear how your TableCellRenderer works, but you might try HTML, which is supported in many Swing components.

Another useful exercise is to prepare an sscce that reproduces the problem in minature. A small, complete example might expose the problem. It would also allow others to test your approach on different platforms.


This answer is probably too late for the one who asked this question, but for everybody with a similar problem, here is my solution;

I had exactly the same problem, I have my own TableCellRenderer to handle multi-line Strings which works flawless for showing the table but makes the printing of the table unreliable. My solutions consists of 2 parts;

Part 1: I have created my own TableModel, in the getValueAt() I 'copied' a part of the StringCellRenderer logic, I make it recalculate and set the height of the table row in case af a multi-line String AND return the String as HTML with 'breaks' instead of line-separators.

Part 2: Before invoking the table.print() I call the getValueAt() for all cells (a for-loop over the columns with an inner for loop over the rows invoking the getValueAt()), this has to be done 'manually' because the print functionality doesn't invoke all getValueAt's (I have found reasons on different fora regarding this issue regarding the execution of the TableCellRenderers).

This way the clipping of the table is done like it is supposed to, only complete rows are printed per page and it devides the rows over severall pages if required with a table header at each page.

0

精彩评论

暂无评论...
验证码 换一张
取 消