Вкладки JTabbedPane настроить внешний вид

Я хочу настроить внешний вид вкладок в JTabbedPane.
Я хочу начать с самого простого и простого поведения: без границ, сплошной цвет.
Проблема в том, что некрасивость все еще остается: вкладки незначительно перекрываются.

enter image description here

вы видите, что, поскольку выбрана вторая вкладка, она "выведена на первый план". Это достигается за счет незначительного перекрытия. Есть (не хитрый) способ отключить это поведение?

простой, проверяемый (просто исправить импорт) код:

public class TabbedPane_LookStudy extends JFrame{

public static void main(String [] args) throws UnsupportedLookAndFeelException {
    UIManager.setLookAndFeel(new NimbusLookAndFeel());
    new TabbedPane_LookStudy().setVisible(true);
}

public TabbedPane_LookStudy() {
    JTabbedPane tp = new JTabbedPane();
    tp.setUI(new MyTabbedPaneUI());
    add(tp);

    tp.addTab("first",new JPanel());
    tp.addTab("second", new JPanel());
    tp.addTab("third", new JPanel());

    setPreferredSize(new Dimension(180,100));
    pack();
}

public static class MyTabbedPaneUI extends javax.swing.plaf.basic.BasicTabbedPaneUI {

    @Override
    protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects, 
               int tabIndex, Rectangle iconRect, Rectangle textRect) {
        Color savedColor = g.getColor();
        g.setColor(Color.PINK);
        g.fillRect(rects[tabIndex].x, rects[tabIndex].y, 
               rects[tabIndex].width, rects[tabIndex].height);
        g.setColor(Color.BLUE);
        g.drawRect(rects[tabIndex].x, rects[tabIndex].y, 
               rects[tabIndex].width, rects[tabIndex].height);
        g.setColor(savedColor);
    }
 }

}

4 ответов


правильным способом было бы реализовать Пользовательский Внешний Вид только. Но если вы хотите играть с XxxTabbedPaneUI, тогда, возможно,этот пост может помочь вам с этим.

на Нимбус будет лучше проверить aephyr депо код


первое (частичное) решение. Я нашел код "позиционирования".
Это метод calculateTabRects на TabbedPaneLayout внутренний класс BasicTabbedPaneUI. Метод чрезвычайно сложен, но хорошим новым является то, что часть, которая "поднимает спереди" вкладку, хорошо прокомментирована и изолирована в своем собственном переопределяемом методе! Это padSelectedTab.

Создать класс, который ничего не делает вместо поднятия компонента, так же просто, как:

    protected class MyTabbedPaneLayout extends TabbedPaneLayout {
        @Override
        protected void padSelectedTab(int tabPlacement, int selectedIndex) {
            //do nothing!
            //super.padSelectedTab(tabPlacement, selectedIndex);
        }
    }

обратите внимание, что это должен быть внутренний класс MyTabbedPane. Он должен быть создан путем переопределения MyTabbedPane.createLayoutManager:

@Override
    protected LayoutManager createLayoutManager() {
        //return super.createLayoutManager();
         return new MyTabbedPaneLayout();
    }

очень легко и на самом деле работает... кроме одного случая. В createLayoutManager инстанцирует TabbedPaneLayout если tabLayoutPolicy является WRAP_TAB_LAYOUT, но создает TabbedPanelScrollLayout если tabLayoutPolicy является SCROLL_TAB_LAYOUT. Последний имеет частная и не защищенный доступ, поэтому невозможно подкласс его!
Мой createLayoutManager реализации теряет прокручивать поведение.


вы можете переопределить paintContentBorderTopEdge в MyTabbedPaneUI, чтобы он не думал, что выбраны какие-либо вкладки. Это не очень приятное решение, но взлом классов UI редко поддается одному в моем опыте:)

@Override
protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
                       int selectedIndex, int x, int y, int w, int h) {
    super.paintContentBorderTopEdge(g, tabPlacement, -1, x, y, w, h);
}

вы можете положить HTML-теги в первый параметр следующим образом :

MyJTabbedPane.addTab("<html><h1 style='padding:20px;'>TEST</h1></html>", new JPanel());