2

I noticed something similar to a bug when using JTabbedPane in Windows Look And Feel (on Windows 10).

The tabbed pane has a grey extra border on the right (2 pixels) and on the left (1 pixel). That border is not visible if the tabbed pane is inside a JPanelwith the default background color (rgb: 240, 240, 240), but it shows up in a panel with a different background color (look screenshot below).

I also want to remove the 3 pixels white border under the tabs.

Screenshot showing a default JTabbedPane

The only similar question i found on SO is this one: JTabbedPane in Windows L&F with unremovable border, but there isn't a solution which actually works (see code below).

In fact, changing TabbedPane.contentBorderInsetscould easily remove the white border below the tabs (by setting insets.top = -1), but it breaks the UI when trying to remove the right border.

I tried different solutions, both using UIManager.opaque and UIManager.background and by manually overriding isOpaque () and getBackground () methods, i also tried to set a null Border, without any positive result.

I think i found a kind of hack which should work on Windows 10, overriding getBorder () method in order to return a MatteBorder with the same extra border dimension and the parent background as border color. Also, to remove the top border under the tabs i'm using:

setBackground ((Color) UIManager.get ("TabbedPane.highlight"));

for the panels inside the tabs.

This is a screnshot (code at the end of the post) which shows some tries i did, the last one is the result which i expected to have:

enter image description here

Is there any better solution to remove that nasty border? I'm afraid the UI could break down on different LAFs with the code i'm using right now ...

Should i create a factory method to check if the current LAF is "Windows", something like:

if (UIManager.getLookAndFeel ().getName ().equals ("Windows") {
    // Create "Custom" JTabbedPane, ovveriding getBorder method and setting panel background ...
}
else {
    // Create default JTabbedPane ...
}

Thanks in advance, here there is the code i used:

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class TabbedPaneTest
{
    public static void main (String [] a) {
        SwingUtilities.invokeLater (new Runnable () {
            @Override public void run () {
                try {
                    UIManager.put ("TabbedPane.focus", new Color (0, 0, 0, 0));
                    UIManager.setLookAndFeel (UIManager.getSystemLookAndFeelClassName ());
                    createAndShowGUI ();
                }
                catch (Exception e) {
                    e.printStackTrace ();
                }
            }
        });
    }
    private static void createAndShowGUI () {
        JFrame frame = new JFrame ("Tabbed Pane Test");
        frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        frame.setContentPane (new MainPanel ());
        frame.pack ();
        frame.setLocationRelativeTo (null);
        frame.setVisible (true);
    }
}
class MainPanel extends JPanel
{
    public MainPanel () {
        String [] labels = {"Default", "Panel background", "Content border insets", "Content opaque", "Matte border/Panel background"};
        Color [] backgrounds = {(Color) UIManager.get ("Panel.background"), Color.WHITE, Color.BLACK, Color.RED};
        setLayout (new GridLayout (backgrounds.length + 1, labels.length, 20, 10));
        for (int i = 0; i < labels.length; i ++) add (new JLabel (labels [i], JLabel.CENTER));
        for (int i = 0; i < backgrounds.length; i ++) {
            for (int j = 0; j < labels.length; j++) {
                JPanel panel = new JPanel (new FlowLayout (FlowLayout.CENTER, 20, 10));
                panel.add (createTabbedPane (j + 1));
                panel.setBackground (backgrounds [i]);
                add (panel);
            }
        }
        setBorder (new EmptyBorder (5, 5, 5, 5));
    }
    private JTabbedPane createTabbedPane (int i) {
        JTabbedPane tabbedPane;
        if (i == 3) {
            Insets oldValue = (Insets) UIManager.get ("TabbedPane.contentBorderInsets");
            UIManager.put ("TabbedPane.contentBorderInsets", new Insets (-1, 2, 2, 2));
            tabbedPane = new JTabbedPane ();
            UIManager.put ("TabbedPane.contentBorderInsets", oldValue);
        }
        else if (i == 4) {
            UIManager.put ("TabbedPane.contentOpaque", false);
            tabbedPane = new JTabbedPane ();
            UIManager.put ("TabbedPane.contentOpaque", true);
        }
        else if (i == 5) {
            tabbedPane = new JTabbedPane () {
                @Override public Border getBorder () {
                    Container parent = getParent ();
                    if (parent == null) return super.getBorder ();
                    return new MatteBorder (0, 0, 1, 2, parent.getBackground ());
                }
            };
        }
        else tabbedPane = new JTabbedPane ();
        JPanel panel1 = new JPanel (new FlowLayout (FlowLayout.LEFT, 80, 50));
        JPanel panel2 = new JPanel (new FlowLayout (FlowLayout.LEFT, 80, 50));
        if (i == 2 || i == 5) {
            Color highlightColor = (Color) UIManager.get ("TabbedPane.highlight");
            panel1.setBackground (highlightColor);
            panel2.setBackground (highlightColor);
        }
        tabbedPane.add ("Tab 1", panel1);
        tabbedPane.add ("Tab 2", panel2);
        return tabbedPane;
    }
}
Ansharja
  • 1,237
  • 1
  • 14
  • 37
  • Any better with `com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel`? – trashgod Oct 10 '17 at 18:43
  • To be honest i don't like NimbusLookAndFeel, and i would prefer not to use it togheter with the system look and feel. I also tried to set BasicTabbedPaneIUI as UI, and i know i could make my own UI, but if possible i want to keep the system look and feel, it looks nice and i think it is more user friendly ... – Ansharja Oct 10 '17 at 19:59

0 Answers0