JTable с многострочным средством визуализации ячеек очень странно - PullRequest
3 голосов
/ 14 мая 2011

У меня есть JTable с настраиваемым рендерером ячеек для многострочных ячеек. Все в порядке, JTable хорошо отображается на экране, и я очень доволен этим, но ночью, когда я попытался просто напечатать его, у меня возникла очень странная проблема. Использование:

table.print (PrintMode.FIT_WIDTH, новый MessageFormat ("..."), новый 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 ]

2 голосов
/ 28 октября 2011

Я полагаю, у вас та же проблема, что и у меня, когда я задал этот вопрос:

Усеченный вывод на печать JTable

Я нашел решение своей проблемы, и я верю, что оно может помочь и вам.
Ответ здесь: Усеченный вывод на печать JTable

Подводя итог моему ответу:

Если ваш TableCellRenderer - единственное место в вашем коде, где вы устанавливаете строки на их правильную высоту, то вы столкнетесь с проблемами, вызванными оптимизацией внутри JTable: JTable вызывает TableCellRenderers только для ячеек, которые были (или являются скоро появится).

Если не все ваши ячейки были отображены на экране, то не все ваши средства визуализации были вызваны, и поэтому не все ваши строки были установлены на желаемую высоту. Поскольку ваши строки не имеют правильную высоту, ваша общая высота JTable неверна. В конце концов, часть определения общей высоты JTable учитывает высоту каждой из строк этой таблицы. Если общая высота JTable неверна, это приводит к усечению печати, поскольку общая высота JTable - это параметр, который учитывается в логике макета печати. ​​

Простой (но, может быть, не совсем чистый) способ исправить это - посетить все ваши средства визуализации клеток перед печатью. Смотрите мой связанный ответ для примера этого. На самом деле я решил сделать посещение визуализатора сразу после заполнения таблицы данными, поскольку это исправляет некоторые ошибки в экстентах полосы прокрутки JTable (в дополнение к исправлению печати).

Причина, по которой таблица выглядит и работает нормально на экране, даже если печать прерывается, заключается в том, что при прокрутке таблицы различные средства визуализации вызываются, когда на экране появляются новые ячейки, и средства визуализации устанавливают соответствующую высоту строки для вновь видимых строк, и различные измерения затем пересчитываются на лету, и в итоге все работает хорошо, когда вы взаимодействуете с таблицей. (Хотя вы можете заметить, что полоса прокрутки « экстент » меняется при прокрутке, чего обычно не должно быть.)

2 голосов
/ 21 февраля 2013

Этот ответ, вероятно, слишком поздно для того, кто задал этот вопрос, но для всех с подобной проблемой вот мое решение;

У меня была точно такая же проблема, у меня есть свой собственный TableCellRenderer для обработки многострочных строк, который работает безупречно для отображения таблицы, но делает печать таблицы ненадежной. Мои решения состоят из 2 частей;

Часть 1. Я создал свою собственную TableModel, в getValueAt () я «скопировал» часть логики StringCellRenderer, я делаю ее пересчет и устанавливаю высоту строки таблицы в случае многострочного String AND вернуть строку в виде HTML с 'breaks' вместо разделителей строк.

Часть 2. Перед вызовом table.print () я вызываю getValueAt () для всех ячеек (цикл for для столбцов с внутренним циклом for для строк, вызывающих getValueAt ()), это должно быть сделано "вручную", потому что функциональность печати не вызывает все getValueAt (я нашел причины на разных форумах по этой проблеме относительно выполнения TableCellRenderers).

Таким образом, вырезка таблицы выполняется так, как и предполагалось, только полные строки печатаются на странице, и она разделяет строки по нескольким страницам, если требуется, с заголовком таблицы на каждой странице.

2 голосов
/ 15 мая 2011

Странно то, что поведение не является детерминированным.

Такое поведение всегда вызывает у меня подозрения неверная синхронизация .

Непонятно, как вашеTableCellRenderer работает, но вы можете попробовать HTML , который поддерживается во многих компонентах Swing.

Другим полезным упражнением является подготовка sscce , которая воспроизводит проблему в миниатюре .Небольшой, полный пример может раскрыть проблему.Это также позволило бы другим проверить ваш подход на разных платформах.

...