Выровнять заголовок JTable по правому краю

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

Спасибо


person Drew Galbraith    schedule 21.09.2011    source источник


Ответы (13)


Вот альтернативный подход к изменению TableCellRenderer таблицы. JTableHeader. Это не является строго необходимым для этого использования, но сводит к минимуму влияние на внешний вид делегата пользовательского интерфейса.

Типичное использование:

JTable table = new JTable(…);
JTableHeader header = table.getTableHeader();
header.setDefaultRenderer(new HeaderRenderer(table));

Пользовательский рендеринг заголовков:

private static class HeaderRenderer implements TableCellRenderer {

    DefaultTableCellRenderer renderer;

    public HeaderRenderer(JTable table) {
        renderer = (DefaultTableCellRenderer)
            table.getTableHeader().getDefaultRenderer();
        renderer.setHorizontalAlignment(JLabel.CENTER);
    }

    @Override
    public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected,
        boolean hasFocus, int row, int col) {
        return renderer.getTableCellRendererComponent(
            table, value, isSelected, hasFocus, row, col);
    }
}
person trashgod    schedule 21.09.2011

Попробуй это:

((DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer())
    .setHorizontalAlignment(JLabel.RIGHT);
person Eng.Fouad    schedule 21.09.2011
comment
ОП запрашивает заголовок, а не ячейки. - person Heisenbug; 21.09.2011
comment
+1 JTableHeader использует TableCellRenderer; setHorizontalAlignment() работают правильно в этом связанном пример. - person trashgod; 21.09.2011
comment
TableCellRenderer не имеет метода setHorizontalAlignment() :( - person Drew Galbraith; 21.09.2011
comment
К сожалению, я упустил из виду необходимость приведения средства визуализации заголовка таблицы; код обновлен. - person trashgod; 21.09.2011
comment
нет необходимости зацикливаться - заголовок имеет только один рендерер по умолчанию :-) - person kleopatra; 21.09.2011
comment
Это более простой подход - person sunil; 02.03.2016

DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) your_jtable.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(0);

Где 0 — центр.

person chathun    schedule 22.02.2013
comment
Вместо 0 предлагаю SwingConstants.CENTER. - person SingleShot; 17.04.2013

Показанный выше HeaderRenderer (2011/sep/21 от trashgod) в сочетании с кодом из Heisenbug (2011/sep/21) будет работать правильно, только если все заголовки выровнены одинаково.

Если вы хотите выровнять разные заголовки по-разному, вам придется использовать следующий код:

int[] alignments = new int[] { JLabel.LEFT, JLabel.RIGHT, JLabel.RIGHT };
for (int i = 0 ; i < jTable.getColumnCount(); i++){
  jTable.getTableHeader().getColumnModel().getColumn(i)
    .setHeaderRenderer(new HeaderRenderer(jTable, alignments[i]));
}

и

private static class HeaderRenderer implements TableCellRenderer {
  DefaultTableCellRenderer renderer;
  int horAlignment;
  public HeaderRenderer(JTable table, int horizontalAlignment) {
    horAlignment = horizontalAlignment;
    renderer = (DefaultTableCellRenderer)table.getTableHeader()
        .getDefaultRenderer();
  }
  public Component getTableCellRendererComponent(JTable table, Object value,
      boolean isSelected, boolean hasFocus, int row, int col) {
    Component c = renderer.getTableCellRendererComponent(table, value,
      isSelected, hasFocus, row, col);
    JLabel label = (JLabel)c;
    label.setHorizontalAlignment(horAlignment);
    return label;
  }
}

То есть:
Установите выравнивание в getTableCellRendererComponent , а не в конструкторе HeaderRenderer.

person pvbemmelen62    schedule 15.11.2012

Что нужно помнить об обертывании заголовков таблиц по умолчанию: не держите ссылку на них.

Если вы (или ваши пользователи) используете тему Windows Classic в Windows 7 и ваше приложение устанавливает системный LAF по умолчанию, ответ, опубликованный @trashgod, может вызвать у вас проблемы.

На него влияет эта ошибка, опубликованная десять лет назад (серьезно) . Если отображается ваша таблица и вы переключаете тему в настройках Windows с Aero Theme на Windows Classic, будет множество NPE. Вы НЕ должны хранить ссылку на средство визуализации, поскольку в какой-то момент она может стать недействительной. Обтекание должно выполняться динамически, как это предлагается в комментариях к отчету об ошибке. Я взял код оттуда и создал следующий исполняемый пример:

import java.awt.*;
import java.lang.ref.WeakReference;
import javax.swing.*;
import javax.swing.table.*;

public class TestFrame extends JFrame {

    private static final boolean I_WANT_THE_BUG_TO_HAPPEN = true;

    public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, InstantiationException, UnsupportedLookAndFeelException {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                int res = JOptionPane.showConfirmDialog(null, "Do you want to use the XP L&F?", "laffo", JOptionPane.YES_NO_OPTION);
                if (res == JOptionPane.YES_OPTION) {
                    try {
                        UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                    } catch (Exception ex) {
                    }
                }
                new TestFrame().setVisible(true);
            }

        });

    }

    public class MyModel extends AbstractTableModel {

        public int getRowCount() {
            return 10;
        }

        public int getColumnCount() {
            return 10;
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            return "" + rowIndex + " X " + columnIndex;
        }

    }

    public class MyJTable extends JTable {

        /**
         *
         */
        private static final long serialVersionUID = -233098459210523146L;

        public MyJTable(TableModel model) {
            super(model);
        }

        public void doSomething() {
            System.out.println("HEHE");
        }
    }

    public class MyAlternativeJTable extends JTable {

        private WeakReference<TableCellRenderer> wrappedHeaderRendererRef = null;
        private TableCellRenderer wrapperHeaderRenderer = null;

        public MyAlternativeJTable(TableModel model) {
            super(model);
        }

        private class MyAlternativeTableColumn extends TableColumn {

            MyAlternativeTableColumn(int modelIndex) {
                super(modelIndex);
            }

            @Override
            public TableCellRenderer getHeaderRenderer() {
                TableCellRenderer defaultHeaderRenderer
                        = MyAlternativeJTable.this.getTableHeader().getDefaultRenderer();
                if (wrappedHeaderRendererRef == null
                        || wrappedHeaderRendererRef.get() != defaultHeaderRenderer) {
                    wrappedHeaderRendererRef
                            = new WeakReference<TableCellRenderer>(defaultHeaderRenderer);
                    wrapperHeaderRenderer
                            = new DecoratedHeaderRenderer(defaultHeaderRenderer);
                }
                return wrapperHeaderRenderer;
            }
        }

        @Override
        public void createDefaultColumnsFromModel() {
            TableModel m = getModel();
            if (m != null) {
                // Remove any current columns
                TableColumnModel cm = getColumnModel();
                while (cm.getColumnCount() > 0) {
                    cm.removeColumn(cm.getColumn(0));
                }

                // Create new columns from the data model info
                for (int i = 0; i < m.getColumnCount(); i++) {
                    TableColumn newColumn = new MyAlternativeTableColumn(i);
                    addColumn(newColumn);
                }
            }
        }
    }

    private JPanel jContentPane = null;
    private JScrollPane jScrollPane = null;
    private JTable table1 = null;
    private JScrollPane jScrollPane1 = null;
    private JTable table2 = null;

    /**
     * This is the default constructor
     */
    public TestFrame() {
        super();
        initialize();
        int res = JOptionPane.showConfirmDialog(null, "Do you want to call updateUI() on the tables ?", "laffo", JOptionPane.YES_NO_OPTION);
        if (res == JOptionPane.YES_OPTION) {
            table2.updateUI();
            table1.updateUI();
        }
    }

    /**
     * This method initializes this
     *
     * @return void
     */
    private void initialize() {
        this.setSize(753, 658);
        this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        this.setContentPane(getJContentPane());
        this.setTitle("JFrame");
    }

    /**
     * This method initializes jContentPane
     *
     * @return javax.swing.JPanel
     */
    private JPanel getJContentPane() {
        if (jContentPane == null) {
            jContentPane = new JPanel();
            jContentPane.setLayout(null);
            jContentPane.add(getJScrollPane(), null);
            jContentPane.add(getJScrollPane1(), null);
        }
        return jContentPane;
    }

    /**
     * This method initializes jScrollPane
     *
     * @return javax.swing.JScrollPane
     */
    private JScrollPane getJScrollPane() {
        if (jScrollPane == null) {
            jScrollPane = new JScrollPane();
            jScrollPane.setBounds(new java.awt.Rectangle(358, 0, 387, 618));
            jScrollPane.setViewportView(getTable1());
        }
        return jScrollPane;
    }

    /**
     * This method initializes table1
     *
     * @return javax.swing.JTable
     */
    private JTable getTable1() {
        if (table1 == null) {
            table1 = new JTable(new MyModel());
        }
        return table1;
    }

    /**
     * This method initializes jScrollPane1
     *
     * @return javax.swing.JScrollPane
     */
    private JScrollPane getJScrollPane1() {
        if (jScrollPane1 == null) {
            jScrollPane1 = new JScrollPane();
            jScrollPane1.setBounds(new java.awt.Rectangle(0, 0, 350, 618));
            jScrollPane1.setViewportView(getTable2());
        }
        return jScrollPane1;
    }

    /**
     * This method initializes table2
     *
     * @return javax.swing.JTable
     */
    private JTable getTable2() {
        if (table2 == null) {
            if (I_WANT_THE_BUG_TO_HAPPEN) {
                table2 = new MyJTable(new MyModel());
                JTableHeader header = table2.getTableHeader();
                TableCellRenderer render = new DecoratedHeaderRenderer(header.getDefaultRenderer());
                header.setDefaultRenderer(render);
            } else {
                table2 = new MyAlternativeJTable(new MyModel());
            }
        }
        return table2;
    }

    private class DecoratedHeaderRenderer implements TableCellRenderer {

        public DecoratedHeaderRenderer(TableCellRenderer render) {
            this.render = render;
        }
        private TableCellRenderer render;

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            Component c = render.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            return c;
        }

    }

}

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

Принятый в настоящее время ответ на этот вопрос широко используется, но он не рекомендуется. Вы можете воспроизвести его с потерянными приложениями, включая Netbeans 8.0.2 (который сам основан на Java), в то время как он показывает сортируемую таблицу, такую ​​​​как Window > IDE Tools > Notifications, где вы также получите отчеты NPE, по иронии судьбы. Просто переключите тему Windows с Aero на Windows Classic (через right-click Desktop > Personalize > Change the visuals and sounds on your computer) в Windows 7.

Если вы используете глазированные списки и вызываете ca.odell.glazedlists.swing.TableComparatorChooser.install, вы также пострадали. Он вводит свой собственный рендерер для сортировки стрелок.

Я случайно наткнулся на это, пытаясь найти решение для этот вопрос, который, я подозреваю, связан.

person predi    schedule 20.04.2016
comment
Отличная работа. Хотел бы я проголосовать за это еще кучу раз. - person kmort; 21.06.2016

DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) 
MSISDNTable.getTableHeader().getDefaultRenderer();
renderer.setHorizontalAlignment(JLabel.RIGHT);

где MSISDNTable это ваш стол

person Mahfuz Ahmed    schedule 01.12.2015

DefaultTableCellRenderer defaultHeaderRenderer = (DefaultTableCellRenderer) getTableHeader().getDefaultRenderer();
defaultHeaderRenderer.setHorizontalAlignment(JLabel.CENTER);         
getTableHeader().setDefaultRenderer(defaultHeaderRenderer);

Я тестировал в JAVA8. работает нормально.

person Sashikant Prasad    schedule 29.07.2020
comment
getTableHeader().setDefaultRenderer(defaultHeaderRenderer);не нужен - person hdvianna; 07.03.2021

Попробуйте этот код,

JTableHeader jtableHeader = jtable.getTableHeader();
DefaultTableCellRenderer rend = (DefaultTableCellRenderer) jtable.getTableHeader().getDefaultRenderer();
rend.setHorizontalAlignment(JLabel.CENTER);
jtableHeader.setDefaultRenderer(rend);
person Kannan Arumugam    schedule 18.09.2013
comment
хм ... ничего нового по сравнению с более ранними ответами, не так ли ;-) Кстати: нет необходимости снова устанавливать средство визуализации по умолчанию, оно уже является средством визуализации по умолчанию - person kleopatra; 18.09.2013

Я создал класс на основе решения pvbemmelen62, который можно очень легко использовать, например:

AlignHeaderRenderer.install(myTable, new int[] { SwingConstants.RIGHT,
                        SwingConstants.RIGHT, SwingConstants.LEFT });

or

AlignHeaderRenderer.install(myTable, 0, SwingConstants.RIGHT);
AlignHeaderRenderer.install(myTable, 1, SwingConstants.RIGHT);

Вот код:

public class AlignHeaderRenderer implements TableCellRenderer {

private final TableCellRenderer renderer;
private final int alignment;

public static void install(final JTable table, final int[] alignments) {
    for (int i = 0; i < alignments.length; ++i)
        install(table, i, alignments[i]);
}

public static void install(final JTable table, final int row,
        final int alignment) {
    table.getTableHeader().getColumnModel().getColumn(row)
            .setHeaderRenderer(new AlignHeaderRenderer(table, alignment));
}

private AlignHeaderRenderer(final JTable table, final int alignment) {
    renderer = table.getTableHeader().getDefaultRenderer();
    this.alignment = alignment;
}

@Override
public Component getTableCellRendererComponent(final JTable table,
        final Object value, final boolean isSelected,
        final boolean hasFocus, final int row, final int col) {
    final Component c = renderer.getTableCellRendererComponent(table,
            value, isSelected, hasFocus, row, col);
    ((JLabel) c).setHorizontalAlignment(alignment);
    return c;
}

}
person Oliver Hoffmann    schedule 22.04.2014

Секрет в том, чтобы использовать средство рендеринга из фиктивной таблицы, чтобы получить правильные L&F, и скопировать выравнивание из средства рендеринга строк реальной таблицы. Таким образом, каждый столбец выравнивается отдельно. Вот код:

table.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer() {
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
        Component c2 = dummy.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
        if (table.getRowCount() > 0) {
            Component c3 = table.getCellRenderer(0, col).getTableCellRendererComponent(table, value, isSelected, hasFocus, 0, col);
            if (c2 instanceof JLabel && c3 instanceof JLabel)
                ((JLabel)c2).setHorizontalAlignment(((JLabel)c3).getHorizontalAlignment());
        }
        return c2;
    }
    private final JTable dummy = new JTable();
});

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

person Adam Gawne-Cain    schedule 03.03.2017

person    schedule
comment
Это то, что у меня было изначально, но, к сожалению, оно переопределяет внешний вид заголовков. Также вы должны использовать класс DefaultTableCellRenderer для объекта рендерера, потому что TableCellRenderer не имеет метода setHorizontalAlighment - person Drew Galbraith; 21.09.2011
comment
Это кладж, но, возможно, вы могли бы получить существующий рендерер, сделать instanceof и привести к DefaultTableCellRenderer перед установкой выравнивания? Или, может быть, есть способ принудительно поставить new() в правильный L&F? - person Kevin Reid; 21.09.2011
comment
На самом деле я был неправ. Я не знаю лучшего способа сделать это. Может быть, @Kevin Reid прав. Давайте подождем и посмотрим, может ли кто-нибудь из гуру свинга рассказать нам об этом немного больше. - person Heisenbug; 21.09.2011
comment
Кажется более надежным установить выравнивание на существующем рендерере, чем пытаться декорировать новый. (Не гуру, просто попутчик.) - person trashgod; 21.09.2011
comment
+1 за критическую оценку подхода. @mKorbel: Я чувствую, что мы все ученики Клеопатры. :-) - person trashgod; 21.09.2011
comment
согласен с Жанетт, ее перекрестное знание API и четкая критика продвинули нас гигантскими шагами вперед, ее знания - бесконечная сокровищница, хммм, вокруг нас есть еще несколько разработчиков Java & Swing API/Frameworks/L&F, а также бывший сотрудник Old.Sun (не уверен ..., но я думаю, что ни у кого нет контракта с нынешним владельцем, что-то происходит в Persons & JavaFX), но только Жанетт является ежедневным участником здесь. - person mKorbel; 21.09.2011

person    schedule
comment
Это не ответ на вопрос. Вы должны пересмотреть это, чтобы включить объяснение того, как и почему это решает заданный вопрос, чтобы другие могли узнать и понять, как применить это к своим собственным проблемам. - person yanman1234; 07.08.2017

person    schedule
comment
Не могли бы вы объяснить, для чего предназначена эта строка кода и почему? Например, как ЦЕНТР выравнивается по правому краю? - person Elliott Frisch; 20.07.2014