Jtable, проблемы с отображением значка сортировки TableHeader с пользовательским рендерером и системным L&F

Я создал собственный рендерер для своего заголовка JTabe, но после сортировки таблицы значок сортировки не появляется, когда я использую системный L&F по умолчанию (в моем случае Windows 8), но значок появляется, когда я использую Java L&F.
С Java L&F:
введите здесь описание изображения

С System L&F:
введите здесь описание изображения

А это средство визуализации моего класса:

private class HeaderRenderer implements TableCellRenderer{
        private final LineBorder lb = new LineBorder(new Color(0, 152, 206));
        private final Dimension dim = new Dimension(150, 25);
        private TableCellRenderer delegate;

        public HeaderRenderer(TableCellRenderer delegate) {
            this.delegate = delegate;
        }

        @Override
        public Component getTableCellRendererComponent(JTable table,Object value, boolean isSelected, boolean hasFocused, int row, int column) {
            Component comp = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocused, row, column);

            if (comp instanceof JLabel) {
                JLabel label = (JLabel) comp;
                label.setBackground(Color.WHITE);
                label.setPreferredSize(dim);
                label.setHorizontalAlignment(SwingConstants.CENTER);
                label.setBorder(lb);
            }

            return comp;
        }

    }

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

JTableHeader tableHeaderCompnoent = table.getTableHeader();
tableHeaderCompnoent.setDefaultRenderer(new HeaderRenderer(tableHeaderCompnoent.getDefaultRenderer()));

ИЗМЕНИТЬ:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;

public class TableRenderingAndSorting extends JFrame {

    private JPanel contentPane;
    private JTable table_1;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TableRenderingAndSorting frame = new TableRenderingAndSorting();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public TableRenderingAndSorting() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 497, 347);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(new BorderLayout(0, 0));

        table_1 = new JTable();
        table_1.setModel(new DefaultTableModel(
            new Object[][] {
                {"1", "Jack", "Developper"},
                {"2", "Richard", "Developper"},
                {"3", "Jassmine", "Developper"},
                {"4", "Tom", "Project leader"},
                {"5", "Anna", null},
            },
            new String[] {
                "Col1", "Col2", "Col3"
            }
        ));
        table_1.setAutoCreateRowSorter(true);
        contentPane.add(new JScrollPane(table_1), BorderLayout.CENTER);
        JTableHeader tableHeaderCompnoent = table_1.getTableHeader();
        tableHeaderCompnoent.setDefaultRenderer(new HeaderRenderer(tableHeaderCompnoent.getDefaultRenderer()));
        table_1.getTableHeader().setDefaultRenderer(new HeaderRenderer(tableHeaderCompnoent.getDefaultRenderer()));
    }

    private class HeaderRenderer implements TableCellRenderer{
        private final LineBorder lb = new LineBorder(new Color(0, 152, 206));
        private final Dimension dim = new Dimension(150, 25);
        private TableCellRenderer delegate;

        public HeaderRenderer(TableCellRenderer delegate) {
            this.delegate = delegate;
        }

        @Override
        public Component getTableCellRendererComponent(JTable table,Object value, boolean isSelected, boolean hasFocused, int row, int column) {
            Component comp = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocused, row, column);

            if (comp instanceof JLabel) {
                JLabel label = (JLabel) comp;
                label.setBackground(Color.WHITE);
                label.setPreferredSize(dim);
                label.setHorizontalAlignment(SwingConstants.CENTER);
                label.setBorder(lb);
            }

            return comp;
        }

    }
}

person SlimenTN    schedule 16.05.2015    source источник
comment
Он (значок сортировки) нормально работает?   -  person MadProgrammer    schedule 16.05.2015
comment
да, с Java L&F работает нормально, но когда я меняю L&F, он не появляется.   -  person SlimenTN    schedule 16.05.2015
comment
Вы устанавливаете L&F при запуске или позже, когда JTable уже отображается (т.е. выбирая системный L&F в меню приложения)?   -  person Axel    schedule 16.05.2015
comment
@Axel Я устанавливаю L&F при запуске приложения (основной класс)   -  person SlimenTN    schedule 16.05.2015
comment
пустые слова без контекста в предложении, чтобы лучше помочь, скорее опубликуйте SSCCE / MCVE, короткий, работоспособный, компилируемый, с жестко запрограммированным значением для JTable / XxxTableModel в локальной переменной, AFAIK Win8 / 8.1 не имеет никаких проблем с / без SystemL & F для сортировки значок   -  person mKorbel    schedule 16.05.2015
comment
TableColumnModel — правильное место для настройки Dimension, XxxRenderer — последнее свойство для этого задания.   -  person mKorbel    schedule 16.05.2015
comment
@mKorbel Я отредактировал свой вопрос, проверьте его, пожалуйста.   -  person SlimenTN    schedule 16.05.2015
comment
+1 за Границы vs. SortIcon, найдите JLabel.setIcon(UIManager.getIcon(current_SORT_ORDER)), обратите внимание на три состояния: ACS, DECS, UNSORTED,   -  person mKorbel    schedule 16.05.2015
comment
@mKorbel Я пробовал это :label.setIcon(UIManager.getIcon(table.getRowSorter().getSortKeys()));, но это не работает   -  person SlimenTN    schedule 16.05.2015
comment
@Slimen Tunis Я уверен, что здесь должно быть что-то о   -  person mKorbel    schedule 17.05.2015
comment
@mKorbel спасибо за ваш ответ, но ответ пользователя 1803551 с трюком jpanl сработал нормально, еще раз спасибо за ваше время :)   -  person SlimenTN    schedule 17.05.2015
comment
@Slimen Tunis Я думаю, что JPanel не подходит JComponet для XxxRenderer, но никто не знает, я бы использовал JLabel с BorderLayout вместо JPanel   -  person mKorbel    schedule 17.05.2015


Ответы (1)


[...] значок сортировки не появляется, когда я использую систему L&F по умолчанию (в моем случае Windows 8), но значок появляется, когда я использую Java L&F.

Разница между L&F по умолчанию (металл) и системным L&F заключается в том, что первый рисует значок сортировки в центре (вертикальное выравнивание) ячейки заголовка, а второй рисует его в верхней части ячейки заголовка.

Далее происходит то, что вы рисуете границу для ячеек заголовка. Граница рисуется от края компонента внутрь, то есть она закрашивает область компонента. Так как для системы L&F иконка сортировки находится на краю, то она закрашивается краем.

Вы можете решить эту проблему, удалив границу или добавив метку к JPanel, которая вместо этого будет обрабатывать границу:

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

    Component comp = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocused, row, column);
    JPanel panel = new JPanel(new BorderLayout());
    if (comp instanceof JLabel) {
        JLabel label = (JLabel) comp;
        label.setBackground(Color.WHITE);
        label.setHorizontalAlignment(SwingConstants.CENTER);
        panel.add(label);
        panel.setBorder(lb);
    }
    return panel;
}

Я удалил setPreferredSize, как отметил @mKorbel, и поле dim должно быть удалено вместе с ним.

Также в строках

JTableHeader tableHeaderCompnoent = table_1.getTableHeader();
tableHeaderCompnoent.setDefaultRenderer(new HeaderRenderer(tableHeaderCompnoent.getDefaultRenderer()));
table_1.getTableHeader().setDefaultRenderer(new HeaderRenderer(tableHeaderCompnoent.getDefaultRenderer()));

2-й и 3-й одинаковые, 3-й можно убрать.

person user1803551    schedule 16.05.2015
comment
хороший catch+1 , -1Mio для label.setPreferredSize(dim); почему бы не повторно использовать значок сортировки JLabel.setIcon и не возиться с непрозрачными JPanel и LayoutManager - person mKorbel; 16.05.2015
comment
@mKorbel Я не добавлял label.setPreferredSize(dim), это было то, что было в ОП. Я просто показал, в чем проблема, и предложил способы ее решения, поскольку они не разместили вопрос или запрос. Я не пытался исправить весь код. Что такое Мио? - person user1803551; 16.05.2015
comment
@ user1803551 -1Mio == -1.000.000,- - person mKorbel; 17.05.2015
comment
@mKorbel Я удалил setPreferredSize. Что касается значка, я думаю, что это просто большая работа, чтобы получить порядок сортировки столбца и правильно установить значок. В любом случае вам придется поиграть с менеджером компоновки, если вы хотите, чтобы значки по-прежнему находились на СЕВЕРЕ. - person user1803551; 17.05.2015
comment
@ user1803551 JLabel имеет два прямых метода для позиционирования текста и значка, это правильная работа для XxxRenderer. - person mKorbel; 18.05.2015