Как обернуть строки в ячейке jtable?

Я пытаюсь реализовать собственный TableRenderer, как описано в этом учебник. Я хотел бы, чтобы средство рендеринга переносило каждый текст, который должен быть длинным для данной ячейки. Идея состоит в том, чтобы использовать TextArea в качестве рендерера, так как он поддерживает перенос строк. Однако следующий код ведет себя не так, как ожидалось:

public class LineWrapCellRenderer  extends JTextArea implements TableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(
            JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column) {
        this.setText((String)value);
        this.setWrapStyleWord(true);            
        this.setLineWrap(true);         
        return this;
    }

}

Я установил этот рендерер с помощью

table.setDefaultRenderer(String.class, new LineWrapCellRenderer());

Но записи ячеек остаются развернутыми. Если я добавлю this.setBackground(Color.YELLOW) к методу getTableCellRendererComponent(), все ячейки станут желтыми, как и ожидалось, но не обернуты.

Любые идеи?

ОБНОВЛЕНИЕ: Как заявил в комментариях Майкл Боргвардт, проблема заключается не в переносе строки, а в высоте строки: строки JTables имеют фиксированный размер, поэтому, если ячейка становится выше (поскольку текст теперь -lined), мы должны увеличить высоту строки. Но сколько? Я проверю, стоит ли это еще одного SO-вопроса. Если нет, я добавлю это решение здесь.

Update2: Следующий код определяет высоту строки (если он помещен в getTableCellRendererComponent()):

int fontHeight = this.getFontMetrics(this.getFont()).getHeight();
int textLength = this.getText().length();
int lines = textLength / this.getColumns() +1;//+1, cause we need at least 1 row.           
int height = fontHeight * lines;            
table.setRowHeight(row, height);

person Arvodan    schedule 08.06.2009    source источник
comment
не меняйте состояние таблицы в рендерере - как в никогда-никогда   -  person kleopatra    schedule 26.10.2012
comment
Дорогая Клеопатра!!! Пожалуйста, дайте нам рабочее решение, а не просто говорите, что вы можете сделать это лучше.   -  person Alessandro Rossi    schedule 01.11.2012
comment
Пожалуйста, проверьте это stackoverflow.com/questions/33937074/jtable-cell- упаковка/   -  person Yougesh    schedule 13.08.2016


Ответы (8)


Проблема в том, что высота строк в JTable фиксирована, так что дело не только в том, что есть обтекающий рендерер; Я не уверен, почему это не так, но если бы это было так, обернутый текст был бы обрезан — или, может быть, это именно то, что вы видите. Чтобы настроить высоту строк, вам нужно установить их индивидуально.

person Michael Borgwardt    schedule 08.06.2009
comment
Кажется, это проблема. После установки для высоты строки большего значения появляется перенос строки. Теперь проблема: как добиться идеального нового роста. - person Arvodan; 08.06.2009
comment
Посмотрите на статью, на которую я ссылаюсь, в ней есть пример кода, который я мог бы легко адаптировать для идеально работающего решения. - person Michael Borgwardt; 08.06.2009
comment
Ссылка, которую вы предлагаете больше не работать ... возможно, аргумент в пользу того, чтобы на самом деле показывать здесь код? - person mike rodent; 26.09.2013

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

http://java.sun.com/docs/books/tutorial/2d/text/drawmulstring.html

import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.BreakIterator;

import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;


public class MultilineTableCell 
    implements TableCellRenderer {
    class CellArea extends DefaultTableCellRenderer {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private String text;
        protected int rowIndex;
        protected int columnIndex;
        protected JTable table;
        protected Font font;
        private int paragraphStart,paragraphEnd;
        private LineBreakMeasurer lineMeasurer;

        public CellArea(String s, JTable tab, int row, int column,boolean isSelected) {
            text = s;
            rowIndex = row;
            columnIndex = column;
            table = tab;
            font = table.getFont();
            if (isSelected) {
                setForeground(table.getSelectionForeground());
                setBackground(table.getSelectionBackground());
            }
        }
        public void paintComponent(Graphics gr) {
            super.paintComponent(gr);
            if ( text != null && !text.isEmpty() ) {
                Graphics2D g = (Graphics2D) gr;
                if (lineMeasurer == null) {
                    AttributedCharacterIterator paragraph = new AttributedString(text).getIterator();
                    paragraphStart = paragraph.getBeginIndex();
                    paragraphEnd = paragraph.getEndIndex();
                    FontRenderContext frc = g.getFontRenderContext();
                    lineMeasurer = new LineBreakMeasurer(paragraph,BreakIterator.getWordInstance(), frc);
                }
                float breakWidth = (float)table.getColumnModel().getColumn(columnIndex).getWidth();
                float drawPosY = 0;
                // Set position to the index of the first character in the paragraph.
                lineMeasurer.setPosition(paragraphStart);
                // Get lines until the entire paragraph has been displayed.
                while (lineMeasurer.getPosition() < paragraphEnd) {
                    // Retrieve next layout. A cleverer program would also cache
                    // these layouts until the component is re-sized.
                    TextLayout layout = lineMeasurer.nextLayout(breakWidth);
                    // Compute pen x position. If the paragraph is right-to-left we
                    // will align the TextLayouts to the right edge of the panel.
                    // Note: this won't occur for the English text in this sample.
                    // Note: drawPosX is always where the LEFT of the text is placed.
                    float drawPosX = layout.isLeftToRight()
                        ? 0 : breakWidth - layout.getAdvance();
                    // Move y-coordinate by the ascent of the layout.
                    drawPosY += layout.getAscent();
                    // Draw the TextLayout at (drawPosX, drawPosY).
                    layout.draw(g, drawPosX, drawPosY);
                    // Move y-coordinate in preparation for next layout.
                    drawPosY += layout.getDescent() + layout.getLeading();
                }
                table.setRowHeight(rowIndex,(int) drawPosY);
            }
        }
    }
    public Component getTableCellRendererComponent(
            JTable table, Object value,boolean isSelected, boolean hasFocus, int row,int column
        )
    {
        CellArea area = new CellArea(value.toString(),table,row,column,isSelected);
        return area;
    }   
}

Он также изменяет высоту строки, но делает это хорошо, только когда этот рендерер используется для одного столбца.

И именно так я использовал его для рендеринга моей таблицы.

final int wordWrapColumnIndex = ...;
myTable = new JTable() {    
    public TableCellRenderer getCellRenderer(int row, int column) {
        if (column == wordWrapColumnIndex ) {
            return wordWrapRenderer;
        }
        else {
            return super.getCellRenderer(row, column);
        }
    }
};
person Alessandro Rossi    schedule 13.04.2010
comment
Я хотел бы использовать этот код в своей программе. Если можно, под какой лицензией я должен включить этот код? - person Alex Bliskovsky; 05.07.2011
comment
Большая часть этого кода взята из общедоступного учебника, который, я полагаю, не должен препятствовать какой-либо политике лицензирования. - person Alessandro Rossi; 04.12.2011
comment
-1 для изменения состояния таблицы в... методе рисования?? Это даже хуже, чем делать это в getXXRendererComp, который уже является абсолютным запретом... и другими запретами: создание нового компонента при каждом вызове, отсутствие реализации подсказок по размеру... иногда должно быть более одного голоса ;- ) - person kleopatra; 26.10.2012
comment
Это делает работу! Я знаю, что изменение высоты ячейки при рисовании потребует нового вызова paint() для всей строки, но я не знаю метода, вызываемого перед paint(), где это возможно сделать. Если вы это сделаете, почему бы вам не дать еще один ответ или не предложить другое решение? - person Alessandro Rossi; 26.10.2012
comment
Делать что-то совершенно неправильно - это... неправильно, даже если кажется, что это работает ;-) Существует достаточно примеров использования textArea в качестве tableCellRenderer, нет необходимости их копировать. - person kleopatra; 26.10.2012
comment
Простого использования JTextArea будет недостаточно для увеличения/уменьшения высоты строки, и я не нашел примеров в своем исследовании. Как я знаю, способ, который предлагает учебник по java, для оценки точной высоты строки для текста требует объекта Graphics, доступного в методе рисования. Покажите нам, что вы можете сделать, чтобы сделать это лучше, пожалуйста!!!! - person Alessandro Rossi; 01.11.2012
comment
Что ж, как сказала @kleopatra, это правда (хотя она не показывает, как это решить). Я думаю, вы можете решить проблему, используя InvokeLater из SwingUtilities, единственное, что вам нужно сделать, это изменить table.setRowHeight(rowIndex,(int) drawPosY); на final int height = (int) drawPosY; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { table.setRowHeight(rowIndex, height); } });`. При этом вы решаете проблему вызова изменения макета пользовательского интерфейса в методе рисования. - person PhoneixS; 29.07.2013
comment
@Alessandro молодец, у тебя 1к повторений! Вам случайно не хочется взглянуть на мою идею ниже (Новая идея...) и сказать мне, есть ли у нее ноги? - person mike rodent; 02.10.2013

В дополнение к этому вопросу я хотел бы поделиться с вами решением для многострочного редактора ячеек. Это немного хакерски (сохраняет ссылку на отредактированную строку), но выполняет свою работу.

import javax.swing.*;
import javax.swing.table.TableCellEditor;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

class MultilineTableCellEditor extends AbstractCellEditor implements TableCellEditor {

    JComponent component = new JTextArea();
    JTable table;
    int lastRowIndex;

    public MultilineTableCellEditor() {
        JTextArea textArea = ((JTextArea) component);
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        textArea.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                super.componentResized(e);
                table.setRowHeight(lastRowIndex, (int) (textArea.getPreferredSize().getHeight()));
            }
        });
        textArea.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                super.keyTyped(e);
                table.setRowHeight(lastRowIndex, (int) (textArea.getPreferredSize().getHeight()));
            }
        });
    }

    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
                                                 int rowIndex, int vColIndex) {
        this.table = table;
        lastRowIndex = rowIndex;

        ((JTextArea) component).setText((String) value);
        component.setFont(table.getFont());

        return component;
    }

    public Object getCellEditorValue() {
        return ((JTextArea) component).getText();
    }
}

Используется так:

    JTable table = new JTable(tableModel) {
        // Cell renderer by Alessandro Rossi (posted as solution to this question)
        MultilineTableCell renderer = new MultilineTableCell();
        MultilineTableCellEditor editor = new MultilineTableCellEditor();

        @Override
        public TableCellRenderer getCellRenderer(int row, int column) {
            if (column == multilineColumn) {
                return renderer;
            }
            return super.getCellRenderer(row, column);
        }

        @Override
        public TableCellEditor getCellEditor(int row, int column) {
            if ( column == multilineColumn ) {
                return editor;
            }
            return super.getCellEditor(row, column);
        }
    };
person Arrvi    schedule 28.01.2015
comment
+1 Я несколько недель искал оболочку строки для редактора, наконец нашел это, и оно отлично сработало для меня. Спасибо! - person ppw; 09.06.2016

Вы можете использовать JLabel в качестве средства визуализации и вставить текст в тег HTML и просто добавить <br>, где это необходимо.

Как использовать HTML в компонентах Swing

person willcodejavaforfood    schedule 08.06.2009

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

import java.awt.Component;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.table.TableCellRenderer;

 public class LineWrapCellRenderer extends JTextArea implements TableCellRenderer {

    @Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
        int row, int column) {
    this.setText((String) value);
    this.setWrapStyleWord(true);
    this.setLineWrap(true);

    int fontHeight = this.getFontMetrics(this.getFont()).getHeight();
    int textLength = this.getText().length();
    int lines = textLength / this.getColumnWidth();
    if (lines == 0) {
        lines = 1;
    }

    int height = fontHeight * lines;
    table.setRowHeight(row, height);

    return this;
 }

}
person sboda    schedule 24.02.2015

Единственный способ правильно реализовать это с помощью Swing (я не знаю о JavaFX: возможно, применимы те же принципы) - это понять и использовать setBounds в компоненте рендерера.

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

import java.awt.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

public class MultiWrapColDemo {
  public static void main(String[] args) throws FileNotFoundException {
    EventQueue.invokeLater(new ShowIt());
  }
}

class ShowIt implements Runnable {
  @Override
  public void run() {
    JTable table = new JTable();
    table.getColumnModel().addColumnModelListener( new WrapColListener( table ) );
    table.setDefaultRenderer( Object.class, new JTPRenderer() );

    // examples:
//    table.setIntercellSpacing( new Dimension( 40, 20 ));
//    table.setIntercellSpacing( new Dimension( 4, 2 ));

    Vector<Vector<String>> dataVector = new Vector<Vector<String>>();
    String lorem1 = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore";
    String lorem2 = "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum";

    for (int i = 0; i < 12; i++) {
      Vector<String> row = null;
      if (i % 4 == 0) {
        row = new Vector<String>(Arrays.asList(new String[] { "iggle", lorem1, "poggle", "poke" }));
      } else if (i % 4 == 1) {
        row = new Vector<String>(Arrays.asList(new String[] { lorem2, "piggle", "poggle", lorem1 }));
      } else if (i % 4 == 2) {
        row = new Vector<String>(Arrays.asList(new String[] { lorem1, "piggle", lorem2, "poke" }));
      } else
        row = new Vector<String>(Arrays.asList(new String[] { "iggle", lorem2, "poggle", lorem2 }));
      dataVector.add(row);
    }
    Vector<String> columnIdentifiers = new Vector<String>(Arrays.asList(new String[] { "iggle", "piggle", "poggle",
        "poke" }));
    table.getTableHeader().setFont(table.getTableHeader().getFont().deriveFont(20f).deriveFont(Font.BOLD));
    ((DefaultTableModel) table.getModel()).setDataVector(dataVector, columnIdentifiers);
    JFrame frame = new JFrame("MultiWrapColTable");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JScrollPane jsp = new JScrollPane(table);
    frame.getContentPane().add(jsp);
    frame.pack();
    frame.setBounds(50, 50, 800, 500);
    frame.setVisible(true);
  }
}


// if the renderer on a column (or the whole table) is not a JTextComponent calculating its preferredSize will not do 
// any wrapping ... but it won't do any harm....
class JTPRenderer extends JTextPane implements TableCellRenderer {
  @Override
  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    setText(value.toString());
    return this;
  }
}

class WrapColListener implements TableColumnModelListener {

  JTable m_table;

  WrapColListener( JTable table ){
    m_table = table;
  }

  void refresh_row_heights() {
    int n_rows = m_table.getRowCount();
    int n_cols = m_table.getColumnCount();
    int intercell_width = m_table.getIntercellSpacing().width;
    int intercell_height = m_table.getIntercellSpacing().height;
    TableColumnModel col_model = m_table.getColumnModel();
    // these null checks are due to concurrency considerations... much can change between the col margin change
    // event and the call to refresh_row_heights (although not in this SSCCE...)
    if( col_model == null ) return;
    // go through ALL rows, calculating row heights
    for (int row = 0; row < n_rows; row++) {
      int pref_row_height = 1;
      // calculate row heights from cell, setting width constraint by means of setBounds...
      for (int col = 0; col < n_cols; col++) {
        Object value = m_table.getValueAt(row, col);
        TableCellRenderer renderer = m_table.getCellRenderer(row, col);
        if( renderer == null ) return;
        Component comp = renderer.getTableCellRendererComponent( m_table, value, false, false,
            row, col);
        if( comp == null ) return;
        int col_width = col_model.getColumn(col).getWidth();
        // constrain width of component
        comp.setBounds(new Rectangle(0, 0, col_width - intercell_width, Integer.MAX_VALUE ));
        // getPreferredSize then returns "true" height as a function of attributes (e.g. font) and word-wrapping
        int pref_cell_height = comp.getPreferredSize().height  + intercell_height;
        if (pref_cell_height > pref_row_height) {
          pref_row_height = pref_cell_height;
        }
      }
      if (pref_row_height != m_table.getRowHeight(row)) {
        m_table.setRowHeight(row, pref_row_height);
      }
    }
  }

  @Override
  public void columnAdded(TableColumnModelEvent e) {
    refresh_row_heights();

  }

  @Override
  public void columnRemoved(TableColumnModelEvent e) {
    // probably no need to call refresh_row_heights

  }

  @Override
  public void columnMoved(TableColumnModelEvent e) {
    // probably no need to call refresh_row_heights

  }

  @Override
  public void columnMarginChanged(ChangeEvent e) {
    refresh_row_heights();
  }

  @Override
  public void columnSelectionChanged(ListSelectionEvent e) {
    // probably no need to call refresh_row_heights

  }

}

Вышеприведенное отлично работает в этом SSCCE... но в реальном мире, с более сложными шрифтами, большим количеством текста и большими таблицами, вы начинаете сталкиваться с проблемами. Поэтому ниже я предлагаю новую версию класса Listener вместе с новой версией рендерера (просто для того, чтобы представить использование сложного шрифта...). Замените их на указанный выше SSCCE, если интересно...

/*
 * This class reflects the fact that 1) when you drag a column boundary using the mouse a very large number of
 * ChangeEvents are generated and 2) with more complex fonts, more text and larger tables ("real world") the amount
 * of computation in calculating the row heights becomes significant and leads to an unresponsive GUI, or worse.
 * This "first" strategy to address this involves setting a pause between the detection of a change event and the
 * refreshing of the rows.  Naturally this involves a Timer, the run() method of which is not the EDT, so it
 * must then submit to EventQueue.invokeLater...
 * The larger the table, the more text involved, and the more complex the fonts... the more ingenuity will have to 
 * be used in coping with the potentially vast amount of computation involved in getting the ideal row heights.  This
 * is in the nature of the beast.  Ideas might involve: 
 * 1) adjusting the row heights immediately only for rows which are visible or likely to be visible (Viewport), and 
 * then making successive calls to EventQueue.invokeLater to deal with all the other rows
 * 2) giving cells a "memory" of their heights as a function of the allowed width.  Unfortunately it will not allow
 * the possibility of interpolating intermediate values because the question of whether a line wraps may hinge on a 
 * single pixel difference, although an imperfect solution to this would be err on the side of caution, i.e. pretend
 * that a column is a little thinner than it is to cause wrapping before it is strictly necessary... particularly when 
 * cells are out of view...
 * ... other ideas...(?)  
 */
class FirstRealWorldWrapColListener implements TableColumnModelListener {

  JTable m_table;
  final static long PAUSE_TIME = 50L;
  java.util.Timer m_pause_timer = new java.util.Timer( "pause timer", true );
  TimerTask m_pause_task;

  class PauseTask extends TimerTask{
    @Override
    public void run() {
      EventQueue.invokeLater( new Runnable(){
        @Override
        public void run() {
          refresh_row_heights();
          System.out.println( "=== setting m_pause_task to null..." );
          m_pause_task = null;
        }});
    }
  }

  FirstRealWorldWrapColListener( JTable table ){
    m_table = table;
  }


  void queue_refresh(){
    if( m_pause_task != null ){
      return;
    }
    System.out.println( "=== scheduling..." );
    m_pause_task = new PauseTask();
    m_pause_timer.schedule( m_pause_task, PAUSE_TIME ); 

  }

  void refresh_row_heights() {

    int n_rows = m_table.getRowCount();
    int n_cols = m_table.getColumnCount();
    int intercell_width = m_table.getIntercellSpacing().width;
    int intercell_height = m_table.getIntercellSpacing().height;
    TableColumnModel col_model = m_table.getColumnModel();
    // these null checks are due to concurrency considerations... much can change between the col margin change
    // event and the call to refresh_row_heights (although not in this SSCCE...)
    if( col_model == null ) return;
    // go through ALL rows, calculating row heights
    for (int row = 0; row < n_rows; row++) {
      int pref_row_height = 1;
      // calculate row heights from cell, setting width constraint by means of setBounds...
      for (int col = 0; col < n_cols; col++) {
        Object value = m_table.getValueAt(row, col);
        TableCellRenderer renderer = m_table.getCellRenderer(row, col);
        if( renderer == null ) return;
        Component comp = renderer.getTableCellRendererComponent( m_table, value, false, false,
            row, col);
        if( comp == null ) return;
        int col_width = col_model.getColumn(col).getWidth();
        // constrain width of component
        comp.setBounds(new Rectangle(0, 0, col_width - intercell_width, Integer.MAX_VALUE ));
        // getPreferredSize then returns "true" height as a function of attributes (e.g. font) and word-wrapping
        int pref_cell_height = comp.getPreferredSize().height  + intercell_height;
        if (pref_cell_height > pref_row_height) {
          pref_row_height = pref_cell_height;
        }
      }
      if (pref_row_height != m_table.getRowHeight(row)) {
        m_table.setRowHeight(row, pref_row_height);
      }
    }
  }

  @Override
  public void columnAdded(TableColumnModelEvent e) {
//    refresh_row_heights();
    queue_refresh();

  }

  @Override
  public void columnRemoved(TableColumnModelEvent e) {
    // probably no need to call refresh_row_heights

  }

  @Override
  public void columnMoved(TableColumnModelEvent e) {
    // probably no need to call refresh_row_heights

  }

  @Override
  public void columnMarginChanged(ChangeEvent e) {
//    refresh_row_heights();
    queue_refresh();
  }

  @Override
  public void columnSelectionChanged(ListSelectionEvent e) {
    // probably no need to call refresh_row_heights

  }

}

// if the renderer on a column (or the whole table) is not a JTextComponent calculating its preferredSize will not do 
// any wrapping ... but it won't do any harm....
class JTPRenderer extends JTextPane implements TableCellRenderer {
  Font m_default_font, m_big_font, m_default_alternate_font, m_big_alternate_font;
  HashMap<AttributedCharacterIterator.Attribute, Object>  m_red_serif_attr_map;
  //
  JTPRenderer() {
    m_default_font = getFont();
    m_big_font = m_default_font.deriveFont(m_default_font.getSize() * 1.5f);
    m_red_serif_attr_map = new HashMap<AttributedCharacterIterator.Attribute, Object >();
    m_red_serif_attr_map.put( TextAttribute.FAMILY, Font.SERIF );
    m_red_serif_attr_map.put( TextAttribute.FOREGROUND, Color.RED );
    m_red_serif_attr_map.put( TextAttribute.WIDTH, TextAttribute.WIDTH_EXTENDED );
    m_default_alternate_font = m_default_font.deriveFont( m_red_serif_attr_map );
    m_big_alternate_font = m_big_font.deriveFont( m_red_serif_attr_map );
    // simpler alternate font:
//    m_default_alternate_font = m_default_font.deriveFont( Font.BOLD | Font.ITALIC );
//    m_big_alternate_font = m_big_font.deriveFont( Font.BOLD | Font.ITALIC );
  }

  @Override
  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    int rc = row + column;
    if( rc % 4 == 2 )
      setFont( rc % 5 == 1 ?  m_big_alternate_font : m_default_alternate_font );
    else 
      setFont( rc % 5 == 1 ?  m_big_font : m_default_font );
    setText(value.toString());
    return this;
  }

}
person mike rodent    schedule 10.10.2013

Напишите заголовки в HTML. Вот пример того, что у меня есть. Единственная проблема, с которой я сталкиваюсь, заключается в том, что мне трудно прокручивать их в JPanel, если я настраиваю высоту заголовков.

    myTable.getColumnModel().getColumn(1).setPreferredWidth(75);
    myTable.getColumnModel().getColumn(1).setHeaderValue("<html><b>Day Of<br>Week</b></html>");
person Greg    schedule 25.04.2012

Как отмечалось выше, необходимо рассчитать высоту строки, но текущее решение можно улучшить. На самом деле, это не работало для меня. jtxt.getColumns() возвращал ноль, вызывая деление на ноль. Вот код, который я считаю более чистым:

// set the width on the jTextArea causing a calc of preferred height
jtxt.setSize(table.getWidth(), Short.MAX_VALUE);
int prefH = jtxt.getPreferredSize().height;
table.setRowHeight(row, prefH);
person porcoesphino    schedule 28.12.2013