Многострочные ячейки JTable с автоматической высотой — очень большая первая строка

Я разрабатываю настольное приложение Java (jdk1.6) с помощью Swing. Моя проблема связана с многострочными ячейками (обтекание текстом) с автоматической настройкой высоты ячейки в JTable.

Я уже мог реализовать эту структуру таким образом:

  • Таблица имеет свой собственный рендерер ячеек.
  • Ячейки JTextArea с wraptext=true
  • Я подсчитываю строки в JTextArea после вставки текста в ячейку и соответствующим образом настраиваю высоту строки связанной строки.
  • Ширина ячейки регулируется автоматически. (от желаемого размера)

2 проблемы с этой структурой:

1) Во время выполнения программы она может считать строки и правильно регулировать высоту строки.

Но при первой инициализации (first setModel()) он вычисляет количество строк "первой ячейки" таблицы, т.е. (0,0), намного больше, чем есть. Я отладил код и обнаружил, что он подсчитывает буквы в тексте и умножает на высоту строки 16 (как если бы ширина ячейки составляла 1 букву). В итоге я получаю очень-очень высокий первый ряд. Остальные ряды в порядке.

Когда я не вставляю текст в (0,0), проблем не возникает.

2) Количество строк не работает, когда я отключаю свойство автоматического изменения размера таблицы и определяю ширину ячеек вручную.

Вот мой рендерер ячеек:

public class MultiLineCellRenderer extends JTextArea implements TableCellRenderer {
private JTable DependentTable;

public MultiLineCellRenderer() {
DependentTable=null;
setLineWrap(true);
setWrapStyleWord(true);
setOpaque(true);
} 

public Component getTableCellRendererComponent(JTable table, Object value,
  boolean isSelected, boolean hasFocus, int row, int column) {      


   (...) //some background color adjustments


   setText((value == null) ? "" : value.toString());


   int numOfLines = getWrappedLines(this); // Counting the lines
   int height_normal = table.getRowHeight(row);// read the height of the row

   if(DependentTable == null) // for this case always null
   {
    if (height_normal < numOfLines*16)
    {
        table.setRowHeight(row,numOfLines*16);
    }
   }
  else
        (...)

return this;

}

Вот как я вычисляю количество строк:

public static int getWrappedLines(JTextArea component)
{
    View view = component.getUI().getRootView(component).getView(0);
    int preferredHeight = (int)view.getPreferredSpan(View.Y_AXIS);
    int lineHeight = component.getFontMetrics( component.getFont() ).getHeight();
    return preferredHeight / lineHeight;
} 

------------------------------------

Я удалил код настройки строк за пределы класса. Теперь у таблицы есть прослушиватель моделей. В это время первый ряд не очень большой. Вызов этого метода работает, но проблема заключается в подсчете перенесенных строк. Каждый раз, когда я заполняю ячейку очень длинным текстом, строка переносится правильно, но мой счетчик возвращает 1. (код счетчика перевернутой строки указан выше. такой же, как и в рендерере. Но там он работал нормально)

вот моя модель слушателя:

public class ModelListener implements TableModelListener {

JTable mainTable;
JTable depTable;

public ModelListener(JTable m, JTable d) {
    mainTable = m;
    depTable = d;
}

public ModelListener(JTable m){
    mainTable = m;
    depTable = null;       
}

public void tableChanged(TableModelEvent tme) {
    int fRow = tme.getFirstRow();
    int col = tme.getColumn();

    JTextArea cellArea = (JTextArea)mainTable.getDefaultRenderer(Object.class);

    int numOfLines = getWrappedLines(cellArea); //countLines();
    int height_normal = mainTable.getRowHeight(fRow);


    System.out.println("h normal:"+height_normal);
    System.out.println("numLines:"+numOfLines);
    System.out.println("value:"+mainTable.getModel().getValueAt(fRow, col));
    System.out.println("width:"+cellArea.getPreferredSize().width);

    if(depTable == null)
    {
        if (height_normal < numOfLines*16)
        {
            mainTable.setRowHeight(fRow,numOfLines*16);
        }
    }
    else
    {
       //(---)
    }
    mainTable.repaint();

}

Результат printlines:

  • PreferredHeight: 15 // из функции обернутых строк
  • lineHeight: 15 // из функции обернутых строк
  • ч нормальный:25
  • количество строк: 1
  • value:looooooooooooooooooooooooonng tesssssssssssssssssssssssst // выглядит как 2 строки
  • ширина: 104

Заранее спасибо :)

Исил


person isilpekel    schedule 05.11.2011    source источник
comment
Не изучал вашу проблему, просто: не не (как в случае "ни-ни-никогда") не меняйте состояние таблицы изнутри средства визуализации. Вместо этого переместите логику изменения размера в другое место: выполните цикл по строкам таблицы, подготовьте средства визуализации со значениями, запросите предпочтительный размер/обтекание строк и установите высоту строк соответственно.   -  person kleopatra    schedule 06.11.2011
comment
Может ли быть так, что JTextArea думает, что это только одна строка? Без установки ширины JTextArea вы никогда не сможете определить, какой высоты она должна быть.   -  person MadProgrammer    schedule 11.07.2012
comment
Но ширина была установлена ​​автоматически, и эта проблема возникает только в индексе (0,0) связанной таблицы, хотя все ячейки получены из одних и тех же классов с одинаковыми свойствами. Я также помню, что установил фиксированное значение ширины ячейки (извините, проект больше не разрабатывается), это не помогло.   -  person isilpekel    schedule 11.07.2012
comment
@kleopatra, не могли бы вы объяснить, почему?   -  person Igor    schedule 20.12.2012
comment
@isilpekel Я тестировал ваш код, и проблема исчезла, если вы последуете совету клеопатры. Поместите код изменения высоты строки в собственный метод, а не в средство визуализации.   -  person DSquare    schedule 01.02.2014
comment
@DSquare спасибо за ответ, но я не могу решить, какой метод работает. У меня больше нет кода. Очевидно, проблема заключалась в плохом дизайне. Ваш ответ будет ориентиром для остальных.   -  person isilpekel    schedule 01.02.2014


Ответы (1)


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

package com.mycompany;

import java.awt.Component;
import java.util.List;

import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.border.EmptyBorder;
import javax.swing.table.TableCellRenderer;

public class MultiLineCellRenderer extends JTextArea implements
TableCellRenderer {

    private static final long serialVersionUID = 1L;
    boolean                     limit               = false;

    public MultiLineCellRenderer() {
        setLineWrap(true);
        setWrapStyleWord(true);
        setOpaque(true);
        setBorder(new EmptyBorder(-1, 2, -1, 2));
        this.limit = false;
        setRows(1);
    }

    public MultiLineCellRenderer(int rows) {
        this();
        setRows(rows);
        this.limit = true;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        setText(value == null ? "" : value.toString());

        int dynamicHeight = getLineCount() > getRows() && this.limit ? getRows() : getLineCount();
        int newHeight = table.getRowHeight() * dynamicHeight;
        if (table.getRowHeight(row) != newHeight) {
            table.setRowHeight(row, newHeight);
        }

        if (isSelected) {
            setForeground(table.getSelectionForeground());
            setBackground(table.getSelectionBackground());
        }
        else {
            setForeground(table.getForeground());
            setBackground(table.getBackground());
        }

        return this;
    }
}
person gantners    schedule 13.08.2015
comment
Небольшой недостаток: количество строк, по-видимому, равно количеству новых строк плюс 1 — если длинные строки переносятся, это, похоже, не учитывается. - person user149408; 03.05.2020