2

I created a custom renderer to my JTabe header but after sorting the table, the sorting icon does not appear when I'm using the default system L&F (in my case windows 8) but the icon appears when I use the Java L&F.
With Java L&F:
enter image description here

With System L&F:
enter image description here

And this is my class renderer:

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;
        }

    }

Use:

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

EDIT:

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;
        }

    }
}
SlimenTN
  • 3,383
  • 7
  • 31
  • 78
  • Does it work (the sort icon) normally? – MadProgrammer May 16 '15 at 08:39
  • yes with Java L&F work normally but when I change the L&F it does not appear. – SlimenTN May 16 '15 at 08:42
  • Are you setting the L&F at startup or later when the JTable is already displayed (ie. by selecting the system L&F from the application menu)? – Axel May 16 '15 at 09:29
  • @Axel I'm setting the L&F at startup of the application (main class) – SlimenTN May 16 '15 at 09:53
  • empty words without context in the sentence, for better help sooner post an SSCCE/MCVE, short, runnable, compilable, with hardcoded value for JTable/XxxTableModel in local variable, AFAIK Win8/8.1 hasn't any issue with/without SystemL&F to sort icon – mKorbel May 16 '15 at 10:52
  • TableColumnModel is right place for setting of Dimension, XxxRenderer is last property for this job – mKorbel May 16 '15 at 10:59
  • @mKorbel I have edited my question, check it please. – SlimenTN May 16 '15 at 11:36
  • +1 for Borders v.s. SortIcon, search for JLabel.setIcon(UIManager.getIcon(currnent_SORT_ORDER)), note there are three states ACS, DECS, UNSORTED, – mKorbel May 16 '15 at 13:04
  • @mKorbel I tried this :"label.setIcon(UIManager.getIcon(table.getRowSorter().getSortKeys()));", but it's not working – SlimenTN May 16 '15 at 15:39
  • @Slimen Tunis [I'm sure that here must be somtehing about](http://stackoverflow.com/search?q=user%3A714968+getSortKeys) – mKorbel May 17 '15 at 07:39
  • @mKorbel thnx for your answer but user1803551's answer with jpanl trick worked fine, thnx again for your time :) – SlimenTN May 17 '15 at 07:43
  • @Slimen Tunis I'm think that JPanel isn't good JComponet for XxxRenderer, [but nobody knows](http://stackoverflow.com/a/6355910/714968), I'd be use JLabel with BorderLayout instead of JPanel – mKorbel May 17 '15 at 08:01

1 Answers1

3

[...] the sorting icon does not appear when I'm using the default system L&F (in my case windows 8) but the icon appears when I use the Java L&F.

The difference between the default L&F (Metal) and the system L&F is that the first one draws the sorting icon in the center (vertical alignment) of the header cell and the latter draws it in top of the header cell.

What happens next is that you draw a border for the header cells. A border is painted from the edge of the component inwards, meaning it paints over the component's area. Since the sorting icon is on the edge for the system L&F, it is painted over by the border.

You can solve this by removing the border, or adding the label to a JPanel which will handle the border instead:

@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;
}

I removed setPreferredSize as noted by @mKorbel and the dim field should be removed with it.

Also, in the lines

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

the 2nd and 3rd are the same, you can remove the 3rd.

user1803551
  • 12,965
  • 5
  • 47
  • 74
  • good catch+1 , -1Mio for label.setPreferredSize(dim);, why not to reuse the sort icon JLabel.setIcon and bothering with opaque JPanel and LayoutManager – mKorbel May 16 '15 at 13:02
  • @mKorbel I didn't add `label.setPreferredSize(dim)`, it was what the OP had. I just showed where the problem is and suggested ways to address it since they didn't post a question or request. I didn't attempt to fix the whole code. What is "Mio"? – user1803551 May 16 '15 at 13:14
  • @user1803551 -1Mio == -1.000.000,- – mKorbel May 17 '15 at 07:40
  • @mKorbel I removed the `setPreferredSize`. As for the icon, I think that it's just a lot of work to get the sort order of the column and set the icon appropriately. You would have to play with the layout manager anyway if you want the icons to still be on the NORTH. – user1803551 May 17 '15 at 18:41
  • @user1803551 JLabel has two direct methods for possitioning text and Icon, this is correct job for XxxRenderer – mKorbel May 18 '15 at 07:11