Выравнивание текста по центру в ячейке JTable с помощью TextAreaRenderer

Я использую TextAreaRenderer для переноса текста в моих JTable ячейках. Однако спецификации моего проекта предусматривают возможность центрирования текста (как по горизонтали, так и по вертикали). Я не могу понять, как это сделать.

Поскольку я уже использую TextAreaRenderer, который extends JTextArea, я не могу расширить DefaultTableCellRenderer, который необходим для доступа к методам setHorizontalAlignment() и setVerticalAlignment() (см. этот вопрос и ответ: Как центрировать значение в ячейке JTable?). Я не могу реализовать DefaultTableCellRenderer, потому что это не интерфейс.

SSCCE с TextAreaRenderer, который я использую:

import java.awt.Component;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class Test {

    public static void main(String args[]) {
        JFrame frame = new JFrame();
        JTable table = new JTable();
        JScrollPane jsp = new JScrollPane(table);
        Object[][] data = new Object[2][2];
        data[0][0] = 1;
        data[0][1] = "Super long text just to illustrate word wrap. Super long text just to illustrate word wrap. Super long text just to illustrate word wrap. Super long text just to illustrate word wrap. Super long text just to illustrate word wrap. Super long text just to illustrate word wrap. Super long text just to illustrate word wrap. Super long text just to illustrate word wrap. ";
        data[1][0] = 2;
        data[1][1] = "Two Lines / Two Lines";
        String[] headers = new String[]{"Digit", "Text"};
        table.setModel(new DefaultTableModel(data, headers) {

            @Override
            public Class<?> getColumnClass(int columnIndex) {
                switch(columnIndex){
                    case 1: return Integer.class;
                    case 2: return String.class;
                    default: return Object.class;
                }
            }
        });
        table.getColumnModel().getColumn(1).setCellRenderer(new TextAreaRenderer());
        frame.add(jsp);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }



    static class TextAreaRenderer extends JTextArea implements TableCellRenderer {

        private final DefaultTableCellRenderer adaptee = new DefaultTableCellRenderer();
        /** map from table to map of rows to map of column heights */
        private final Map cellSizes = new HashMap();


        public TextAreaRenderer() {
            setLineWrap(true);
            setWrapStyleWord(true);
        }

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

            // set the colours, etc. using the standard for that platform
            adaptee.getTableCellRendererComponent(table, obj,
                    isSelected, hasFocus, row, column);
            setForeground(adaptee.getForeground());
            setBackground(adaptee.getBackground());
            setBorder(adaptee.getBorder());
            setFont(adaptee.getFont());
            setText(adaptee.getText());


            // This line was very important to get it working with JDK1.4
            TableColumnModel columnModel = table.getColumnModel();
            setSize(columnModel.getColumn(column).getWidth(), 100000);
            int height_wanted = (int) getPreferredSize().getHeight();
            addSize(table, row, column, height_wanted);
            height_wanted = findTotalMaximumRowSize(table, row);
            if (height_wanted != table.getRowHeight(row)) {
                table.setRowHeight(row, height_wanted);
            }
            return this;
        }

        @SuppressWarnings("unchecked")
        private void addSize(JTable table, int row, int column, int height) {
            Map rows = (Map) cellSizes.get(table);
            if (rows == null) {
                cellSizes.put(table, rows = new HashMap());
            }
            Map rowheights = (Map) rows.get(new Integer(row));
            if (rowheights == null) {
                rows.put(new Integer(row), rowheights = new HashMap());
            }
            rowheights.put(new Integer(column), new Integer(height));
        }

        /**
         * Look through all columns and get the renderer.  If it is
         * also a TextAreaRenderer, we look at the maximum height in
         * its hash table for this row.
         */
        private int findTotalMaximumRowSize(JTable table, int row) {
            int maximum_height = 0;
            Enumeration columns = table.getColumnModel().getColumns();
            while (columns.hasMoreElements()) {
                TableColumn tc = (TableColumn) columns.nextElement();
                TableCellRenderer cellRenderer = tc.getCellRenderer();
                if (cellRenderer instanceof TextAreaRenderer) {
                    TextAreaRenderer tar = (TextAreaRenderer) cellRenderer;
                    maximum_height = Math.max(maximum_height,
                            tar.findMaximumRowSize(table, row));
                }
            }
            return maximum_height;
        }

        private int findMaximumRowSize(JTable table, int row) {
            Map rows = (Map) cellSizes.get(table);
            if (rows == null) {
                return 0;
            }
            Map rowheights = (Map) rows.get(new Integer(row));
            if (rowheights == null) {
                return 0;
            }
            int maximum_height = 0;
            for (Iterator it = rowheights.entrySet().iterator();
                    it.hasNext();) {
                Map.Entry entry = (Map.Entry) it.next();
                int cellHeight = ((Integer) entry.getValue()).intValue();
                maximum_height = Math.max(maximum_height, cellHeight);
            }
            return maximum_height;
        }
    }
}

person ryvantage    schedule 21.12.2013    source источник


Ответы (1)


Вам нужно иметь средство визуализации, которое использует JTextPane, а не JTextArea, а затем установить атрибуты стиля документа.

i.e.,

static class TextAreaRenderer extends JTextPane implements TableCellRenderer {

  private final DefaultTableCellRenderer adaptee = new DefaultTableCellRenderer();
  /** map from table to map of rows to map of column heights */
  private final Map cellSizes = new HashMap();

  public TextAreaRenderer() {
     // !! setLineWrap(true);
     // setWrapStyleWord(true);

     StyledDocument doc = getStyledDocument();
     SimpleAttributeSet center = new SimpleAttributeSet();
     StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
     doc.setParagraphAttributes(0, doc.getLength(), center, false);
  }

Для получения дополнительной информации см. (и проголосуйте) ответ camickr здесь.

person Hovercraft Full Of Eels    schedule 21.12.2013
comment
идеально! Спасибо HFOE. - person ryvantage; 21.12.2013
comment
Я видел ответ camickr, но я использовал JTextArea, и это не сработало. JTextPane сделал свое дело. - person ryvantage; 21.12.2013
comment
И последняя проблема: мне нужно, чтобы текст был также центрирован по вертикали. Есть ли способ сделать это? - person ryvantage; 21.12.2013
comment
@ryvantage: Google показал мне это, что может помочь. - person Hovercraft Full Of Eels; 21.12.2013
comment
+1, @ryvantage, I need the text to be centered vertically also. Is there a way to do that? - я в замешательстве. Я думал, ты сказал I did see camickr's answer. Вы прочитали весь ответ? Он показывает, как горизонтальное и вертикальное центрирование. Он имеет ту же ссылку на решение stanislavl, что и ссылка выше. - person camickr; 22.12.2013
comment
@camickr, я не видел весь твой ответ, извини. Когда первые 10 минут копирования/вставки/соответствия/этого не работают, я не думаю, что смог пройти ваше редактирование. Я просто пошел в неправильном направлении с вашим ответом в первый раз, когда я посмотрел. знак равно - person ryvantage; 22.12.2013