2

I have a JTable in my program and I wanted to change the color of the JTableHeader. I did this using the following code

JTableHeader header = table.getTableHeader();
header.setBackground(Color.WHITE);

However, when I dragged the header, I noticed that there was a grey area behind the header as shown in the photo below.

enter image description here

How can I set this to white so that it fits in with my JTableHeader?

MCVE

import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.JTableHeader;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
public class JTableTest extends JFrame {
    private JTableTest()  {
        super("JTable Test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new GridLayout(1, 1));
        createPanel();
        pack();
        setVisible(true);
    }

    JPanel panel = new JPanel(new GridLayout(1, 1));
    JScrollPane scroll = new JScrollPane();

    private void createPanel() {
        Object[] headers = {"Select", "Title", "Artist", "Length"};
        Object[][] sampleData = {{true, "Bat Outta Hell", "Meat Loaf", "673"},
                {false, "Spanish Train", "Chris De Burgh", "358"}};
        JTable table = new JTable(sampleData, headers);
        ///
        JTableHeader header = table.getTableHeader();
        header.setBackground(Color.WHITE); //Sets header white
        ///
        scroll.getViewport().add(table);
        scroll.getViewport().setBackground(Color.WHITE); //Sets table container white
        panel.add(scroll);
        panel.setBackground(Color.WHITE); //Sets scroll pane container white
        getContentPane().add(panel);
        getContentPane().setBackground(Color.WHITE); //Sets panel container white
        //What should be set to white to make header container white
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater (
            new Runnable() {
                @Override
                public void run() {
                    new JTableTest();
                }
            }
        );
    }
}
Dan
  • 7,286
  • 6
  • 49
  • 114
  • Check out: http://stackoverflow.com/questions/40651526/jscrollpane-prevents-components-shrinking-below-their-preferred-size – camickr Nov 20 '16 at 02:17
  • @camickr I'm sorry I'm not quite sure what that answers says about this specific case. Are you referring to `jsp.getViewport().setBackground(Color.WHITE);` because that didn't make any difference with this part? Or are you referring to `ScrollablePanel`? – Dan Nov 20 '16 at 12:05
  • @camickr Sorry, I did read it and I do normally drop a comment (just not this time apparently) – Dan Nov 20 '16 at 19:56
  • I wasn't sure you read that answer because you never commented whether the suggestion helped or not. So I wasn't going to spend time answering this question wondering if you would ever reply to this one as well. In any case I don't see a problem using JDK8 on Widows 7. Maybe it is a version/platform issue? Or maybe the problem is your code which you don't show? – camickr Nov 20 '16 at 19:56
  • @camickr Tested on Windows 8.1 with JDK 8 (latest version). The background when dragging column headers is indeed grey, not white. I mean the background of the container of the header columns, not the header columns themselves. – TT. Nov 20 '16 at 19:57
  • Didn't notice the newly posted code. Anyway I retested with the newly posted SSCCE and I still don't have a problem. `What should be set to white to make header container white?` - the header is part of the scroll pane, so you can try making the scrollpane white. – camickr Nov 20 '16 at 20:04
  • @camickr I did, `scroll.getViewport().setBackground(Color.WHITE);`, unfortunately it did not make a difference. As you see it as white how would you change to code to make it red? And just in case it is an OS difference I am on Windows 10 using JDK 8 – Dan Nov 20 '16 at 20:05
  • @camickr Same, tried that and `scroll.setBackground` and all sorts of UIManager color defaults etc. Can't seem to get that header container background white when dragging columns. – TT. Nov 20 '16 at 20:12
  • Oops, sorry I was only resizing the columns, not dragging them. Yes when I drag the columns I indeed see the grey background. I am confused why this is happening. My understanding of JScrollPane is that it is like a panel with a custom layout manager that supports components like a row header(left), column header(top), scrollbars(right/bottom) and a viewport(center). So I was thinking that maybe the column header is added to a wrapper panel of some kind, but when I invoke getParent() on the header it says the viewport is the parent. Doesn't make sense to me? – camickr Nov 20 '16 at 20:28

1 Answers1

3

Well as I expected we need to set the parent of the header to be the background color you want.

However the scroll pane is NOT the parent of the header as I expected.

When I added code like the following:

System.out.println( header.getParent() );

it showed a JViewport as the parent which confused me.

However when I added:

System.out.println( scroll.getViewport() );

I noticed that the two viewports were different. So it appears the viewport of the scrollpane is different than the viewport of the header.

so the solution to the problem is:

JTableHeader header = table.getTableHeader();
header.setBackground(Color.GREEN); 

and then AFTER the frame is visible you can do:

header.getParent().setBackground(Color.YELLOW);

(I used different colors just to show the effects of each statement)

Note the header is not added to the scrollpane until the frame is packed or made visible. If you try to set the background when the table is created you will get a NPE when trying to access the parent.

Or another option is to add an AncestorListener to the JTableHeader. Then the code can be invoked then header is added to a visible frame. For this type of approach check out the Request Focus Listener found in Dialog Focus

camickr
  • 321,443
  • 19
  • 166
  • 288
  • 1
    Thank you. I just got this to work. I added a `MouseAdapter` on the header so as the first click went down on it, it set the color. Is there a better way to do this as when I created the frame then made `JTable` after the frame was visible I still got the NPE. (Probably did something wrong somewhere but just checking) – Dan Nov 20 '16 at 21:50
  • 2
    `Is there a better way` - I already gave you one (by using the AncestorListener) so the code is only executed once. Also creating a JTable is not enough. The table needs to be added to a scrollpane. – camickr Nov 20 '16 at 22:28
  • Thanks you for the help. I appreciate it – Dan Nov 20 '16 at 22:28
  • I know you suggested using an `AncestorListener` to implement this code but is `EventQueue.invokeLater(() -> header.getParent().setBackground(Color.WHITE));` a better way to do it? – Dan Dec 08 '16 at 15:39
  • 1
    @Dan, Setting of the background of all the components, (table, header, viewport) should all be done in the same logical block of code. Using the invokeLater() does this in a single line of code as oppose to using an anonymous AncestorListener. Using invokeLater() means you must then use pack(), setVisible() on the window in the same block of code. I suppose this is true in 99.9% of the time but basically you have built in a logical dependency on the order of execution of your code. Probably not a big deal, just wanted to point out the subtle difference. – camickr Dec 08 '16 at 16:37