java JTabbedPane 自定义选项卡外观

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7859035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 21:43:45  来源:igfitidea点击:

JTabbedPane customize tab look

javaswingjtabbedpane

提问by AgostinoX

I want to customize the look of the tabs in JTabbedPane.
I want to start from the simplest and plainest behavior: no borders, solid color.
The problem is that a non-plainess still remains: the tabs slight margin overlap.

我想自定义 JTabbedPane 中选项卡的外观。
我想从最简单最朴素的行为开始:无边框,纯色。
问题是仍然存在一个不平的地方:标签页边距略有重叠。

enter image description here

在此处输入图片说明

You see that since the second tab is selected, it is "brought to the fore". This is achieved by a slight margin overlap. Is there a (non tricky) way to disable this behavior?

您会看到,由于选择了第二个选项卡,因此它被“带到了前台”。这是通过轻微的边缘重叠来实现的。有没有(非棘手的)方法来禁用这种行为?

simple, testable (just fix imports) code:

简单,可测试(只需修复导入)代码:

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

}

}

采纳答案by mKorbel

Correct way would be to implement Custom Look & Feelonly. But if you want to play with XxxTabbedPaneUI, then maybe this postcan help you with that.

正确的方法是仅实现自定义外观。但是如果你想玩XxxTabbedPaneUI,那么也许这篇文章可以帮助你。

for Nimbuswill be better to check aephyrcode depot

对于Nimbus会更好地检查aephyr代码仓库

回答by AgostinoX

First (partial) solution. I've located the "positioning" code.
It is the method calculateTabRectsin TabbedPaneLayout, an inner class of BasicTabbedPaneUI. The method is extremely complex, but the good new is that the part that "raises in front" the tab is well commented and insulated in its own overridable method! It is padSelectedTab.

Create a class that does nothing instead of raising the component is as simple as:

第一个(部分)解决方案。我已经找到了“定位”代码。
这是该方法calculateTabRectsTabbedPaneLayout,一个内部类BasicTabbedPaneUI的。该方法极其复杂,但好消息是“在前面提出”选项卡的部分在其自己的可覆盖方法中得到了很好的注释和绝缘!它是padSelectedTab

创建一个什么都不做而不是提升组件的类就像这样简单:

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

Notice that it has to be an inner class of MyTabbedPane. It has to be instantiated by overriding MyTabbedPane.createLayoutManager:

请注意,它必须是 MyTabbedPane 的内部类。它必须通过覆盖 MyTabbedPane.createLayoutManager 来实例化:

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

Very easy and actually working... except for a case. The createLayoutManager instantiates TabbedPaneLayout if the tabLayoutPolicy is WRAP_TAB_LAYOUT, but instantiates TabbedPanelScrollLayout if tabLayoutPolicy is SCROLL_TAB_LAYOUT. The latter has privateand not protected access, so it is not possible subclass it!
My createLayoutManager implmentation looses scrollable behavior.

非常简单且实际工作......除了一个案例。如果 tabLayoutPolicy 是 WRAP_TAB_LAYOUT,则 createLayoutManager 实例化 TabbedPaneLayout,但如果 tabLayoutPolicy 是 SCROLL_TAB_LAYOUT,则实例化 TabbedPanelScrollLayout。后者具有私有且不受保护的访问权限,因此不可能将其子类化!
我的 createLayoutManager 实现失去了可滚动行为。

回答by Mike Lowry

You can put Html tags into the first parameter as following :

您可以将 Html 标签放入第一个参数中,如下所示:

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

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

回答by kylewm

You can override paintContentBorderTopEdge in MyTabbedPaneUI so that it doesn't think any of the tabs are selected. This is not a pretty solution, but hacking UI classes rarely lends itself to one in my experience :)

您可以在 MyTabbedPaneUI 中覆盖 paintContentBorderTopEdge,这样它就不会认为任何选项卡被选中。这不是一个很好的解决方案,但根据我的经验,黑客 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);
}