How can I set a JLabel's background and border the same as a table header?
Asked Answered
S

4

2

I want to recreate a table header looks using JLabel. The look and feel of the JLabel needs to be exactly like the JTableHeader would be, specified by the system.

This is what I have tried so far:

JLabel header = new JLabel("Title");
header.setOpaque(true);
header.setBackground(UIManager.getColor(new JTableHeader().getBackground()));
header.setBorder(UIManager.getBorder(new JTableHeader().getBorder()));

But, the UIManager returns null for the color and border.

Any ideas?

This is how I set the Look and Feel:

javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
Sela answered 3/11, 2012 at 21:49 Comment(5)
Color and BorderUIResource, dependes of used L&F, could be important, for Metal doeasn't matterBrett
@Brett Could you be more clear please?Sela
check whats returned, for official Sun/Oracle L&FsBrett
@Brett This: java.swing.plaf.BorderUIResource$CompoundBorderUIResouce@fadfa for the border. Can I use it somehow?Sela
@Brett in the app you suggested, if you choose "Windows" in the look and feel menu, and select the TableHeader item, you'll see components that looks like Windows classic. But, the table header they are shown in has a different look, that's the look I'm after.Sela
C
4

There are more issues involved then just getting the color and border of the table header. Each cell/column is rendered by a TableCellRenderer meaning that the values return by the UIManager may be ignored...

For example, the following renders the JTableHeader and applies border/background to a JLabel based on values returned by the UIManager under the Window's Look and Feel...

enter image description here

As you can see, there's quite a difference between them

How ever, if all you're interested in is display a "group header" of some kind over the top of another component on a scroll pane, you could simply add a JTableHeader to the scroll panes column view directly...

enter image description here

public class TestHeader {

    public static void main(String[] args) {
        new TestHeader();
    }

    public TestHeader() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                TableColumnModel model = new DefaultTableColumnModel();
                final TableColumn column = new TableColumn(0, 250);
                column.setHeaderValue("Test");
                model.addColumn(column);

                JTableHeader header = new JTableHeader();
                header.setColumnModel(model);

                final JTextArea textArea = new JTextArea();

                JScrollPane scrollPane = new JScrollPane(textArea);
                scrollPane.setColumnHeaderView(header);

                textArea.addComponentListener(new ComponentAdapter() {
                    @Override
                    public void componentResized(ComponentEvent e) {
                        column.setWidth(textArea.getWidth());
                    }
                });

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(scrollPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

UPDATED

enter image description here

public class TestHeader {

    public static void main(String[] args) {
        new TestHeader();
    }

    public TestHeader() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                TableColumnModel model = new DefaultTableColumnModel();
                final TableColumn column = new TableColumn(0, 250);
                column.setHeaderValue("I don't see the problem");
                model.addColumn(column);

                final JTableHeader header = new JTableHeader();
                header.setColumnModel(model);

                DefaultTableModel tm = new DefaultTableModel(new Object[]{"A", "B", "C"}, 0);
                tm.addRow(new Object[]{"1", "2", "3", "4"});
                tm.addRow(new Object[]{"5", "6", "7", "8"});
                tm.addRow(new Object[]{"9", "10", "11", "12"});
                tm.addRow(new Object[]{"13", "14", "15", "16"});
                final JTable table = new JTable(tm);

                final JScrollPane scrollPane = new JScrollPane(table);
                /**
                 * For some reason, the header isn't being applied as soon as the
                 * table is added to the scroll pane, so we need to jump our next
                 * request to the end of the of event queue so that it will
                 * occur some time in the future
                 */
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        scrollPane.setColumnHeaderView(header);
                    }

                });

                table.addComponentListener(new ComponentAdapter() {
                    @Override
                    public void componentResized(ComponentEvent e) {
                        column.setWidth(table.getWidth());
                    }

                });

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(scrollPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

}
Contracted answered 5/11, 2012 at 4:36 Comment(13)
Works fine with JTextArea, but if you replace it with JTable, the header doesn't show at all. This would be useful if you wanted to replace the 2 headers in a 2 column table with only 1 header.Sela
Is there any way to make this work with a JTable instead of the JTextArea?Sela
What do you mean? JTable automatically configures the column headerContracted
Can the JtableHeader from the table be hidden and a new header added to the scrollpane? Or is it the same header we are talking about? I want to remove the headers from a 2 column table and put a single header over the two columns.Sela
Sure, after you've added the table to scroll pane, you should be able to use the technique above to replace the eating headerContracted
Yes it does, there is a slight of hand involved though - check update to answerContracted
Nice! I hope the thread won't be causing any problems later on.Sela
It's not a thread. invokeLater places a runnable directly on the event queue, which is then executed, at some time in the future on the EDT ;)Contracted
Turns out runnable does cause a problem after all. At first, it's all OK, but when I replace the JPanel that contains the tables, from the right side of a JSplitPane, with another JPanel and then the replace this one with the first one again - the old table headers come back. Do you have any idea why this happens?Sela
@igor each time a table is added to a scroll pane, it installs it headers. If this is major issue, you can extend from JTable and override configureEnclosingScrollPane, to will allow you the opportunity to replace the header with your own implementationContracted
Thanks again. I think I've fixed it. I removed the runnable and just added this: scrollPane.setColumnHeaderView(header); //Add the header to the ScrollPane table.setTableHeader(header); // Add this header to the table aswell I don't know why but seems like it works.Sela
BTW, you don't happen to be familiar with Advanced RTFEditorKit do you? java-sl.com/advanced_rtf_editor_kit.htmlSela
@Sela No, I'm not farmular with it, but it looks interestingContracted
D
2

You need to set a look and feel for the application before trying:

header.setBackground(UIManager.getColor(new JTableHeader().getBackground()));
header.setBorder(UIManager.getBorder(new JTableHeader().getBorder()));

you should set a look and feel first like so:

  try {
    for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
        if ("Nimbus".equals(info.getName())) {
            UIManager.setLookAndFeel(info.getClassName());
            break;
        }
    }
} catch (Exception e) {
    // If Nimbus is not available, you can set the GUI to another look and feel.
}

Here is an example:

enter image description here

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.JTableHeader;

public class Test {

    public Test() {
        initComponents();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    //set nimbus look and feel
                    for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                        if ("Nimbus".equals(info.getName())) {
                            UIManager.setLookAndFeel(info.getClassName());
                            break;
                        }
                    }
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
                    e.printStackTrace();
                }

                new Test();
            }
        });
    }

    private void initComponents() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JLabel header = new JLabel("Title");
        header.setBackground(UIManager.getColor(new JTableHeader().getBackground()));
        header.setBorder(UIManager.getBorder(new JTableHeader().getBorder()));

        frame.add(header);

        frame.pack();
        frame.setVisible(true);
    }
}
Delmadelmar answered 3/11, 2012 at 22:13 Comment(5)
I did set the look and feel: setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());Sela
@Sela Your systems look and feel might not have a border color. I'd suggest using a Java L&F for this exact case as they all seem to work fineDelmadelmar
Ofcourse they do - how would JTableHeader be shown if they didn't?Sela
@Sela I cannot say for sure but what I mean is it does not have a color for JTable borders (this is no real clash to the system it just does not use a border than) I even left out the call in my example to the border coour and it still looked identicalDelmadelmar
Could you set your example to "Windows" look and feel and create a JTable and see if it would be the same? I think it might be a coincidence that they are the same in Nimbus.Sela
A
2

Try taking the defaults from UIManager:

Color color = UIManager.getColor("TableHeader.background");
Border border = UIManager.getBorder("TableHeader.CellBorder");
Advertisement answered 3/11, 2012 at 22:14 Comment(5)
Aw shucks, 1+ to both of you and the OP.Herra
@Max The returned color is RGB(240,240,240) and the border is null. I'm on PC.Sela
@Sela the value depends on look and feel. What LaF are you using ?Advertisement
@Max The look and feel is set according to the system. I'm on PC, so I'm using the "windows" L&F.Sela
Strange, for Windows it returns javax.swing.plaf.ColorUIResource[r=240,g=240,b=240]. See UIManager Defaults by @camickr for details.Advertisement
S
0

I figured I'll create a JTable without any rows and place a JTextPane right underneath. And it works like charm.

JTextPane textPane = new JTextPane();
JPanel panel = new JPanel(new BorderLayout());

JTable table = new JTable(0, 1);
table.setPreferredScrollableViewportSize(new Dimension(600, 0));
JScrollPane js = new JScrollPane(table)

panel.add(js, BorderLayout.NORTH);
panel.add(new JScrollPane(textPane),BorderLayout.CENTER);
Sela answered 3/11, 2012 at 23:36 Comment(1)
If you're just going to do that, just create JTableHeader with a single column and add it to the scroll pane's column headerContracted

© 2022 - 2024 — McMap. All rights reserved.