在JTabbedPane标头中添加JLabel

时间:2012-05-16 14:24:37

标签: java swing jlabel jdialog jtabbedpane

我有一个带有JTabbedPane的JDialog:

enter image description here

我只想在JTabbedPane的右上角区域添加一个JLabel,这样我就可以触发一些事件(例如关闭JDialog)。 我不想把它变成JFrame。

PS:我知道这可能是重复的,但没有一个回复给我一个解决方案。

2 个答案:

答案 0 :(得分:8)

嗯,实际上在Swing中不支持JTabbedPane中的定位。但你总是可以通过布局和图层制作一些街头魔术:

public static void main ( String[] args )
{
    try
    {
        UIManager.setLookAndFeel ( UIManager.getSystemLookAndFeelClassName () );
    }
    catch ( Throwable e )
    {
        e.printStackTrace ();
    }

    JFrame frame = new JFrame ();
    frame.setUndecorated ( true );

    frame.setLayout ( new LayoutManager ()
    {
        private List<Component> special = new ArrayList<Component> ();

        public void addLayoutComponent ( String name, Component comp )
        {
            if ( name != null )
            {
                special.add ( comp );
            }
        }

        public void removeLayoutComponent ( Component comp )
        {
            special.remove ( comp );
        }

        public Dimension preferredLayoutSize ( Container parent )
        {
            Dimension ps = new Dimension ();
            for ( Component component : parent.getComponents () )
            {
                if ( !special.contains ( component ) )
                {
                    Dimension cps = component.getPreferredSize ();
                    ps.width = Math.max ( ps.width, cps.width );
                    ps.height = Math.max ( ps.height, cps.height );
                }
            }
            return ps;
        }

        public Dimension minimumLayoutSize ( Container parent )
        {
            return preferredLayoutSize ( parent );
        }

        public void layoutContainer ( Container parent )
        {
            Insets insets = parent.getInsets ();
            for ( Component component : parent.getComponents () )
            {
                if ( !special.contains ( component ) )
                {
                    component.setBounds ( insets.left, insets.top,
                            parent.getWidth () - insets.left - insets.right,
                            parent.getHeight () - insets.top - insets.bottom );
                }
                else
                {
                    Dimension ps = component.getPreferredSize ();
                    component.setBounds ( parent.getWidth () - insets.right - 2 - ps.width,
                            insets.top + 2, ps.width, ps.height );
                }
            }
        }
    } );

    final JTabbedPane tabbedPane = new JTabbedPane ();
    tabbedPane.addTab ( "Tab1", new JLabel () );
    tabbedPane.addTab ( "Tab2", new JLabel () );
    tabbedPane.addTab ( "Tab3", new JLabel () );
    frame.add ( tabbedPane );

    final JLabel label = new JLabel ( "Close X" );
    label.addMouseListener ( new MouseAdapter ()
    {
        public void mousePressed ( MouseEvent e )
        {
            System.exit ( 0 );
        }
    } );
    frame.add ( label, "special", 0 );

    frame.setSize ( 200, 150 );
    frame.setLocationRelativeTo ( null );
    frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
    frame.setVisible ( true );
}

这可以在任何地方使用,没有任何问题。请注意,标签将始终位于右上角,并且不会定位自己(除非您修改代码以支持更多“功能”)在其他OS LaF上,例如Mac OS laf,其中选项卡可能位于中间。如果它们与标签交叉,它也将被涂在标签上。

所以你会得到这样的东西:

enter image description here

无论如何,您可以轻松修改应用于布局内部的JLabel边界以制作一些侧面间距等...

答案 1 :(得分:3)

这可以通过扩展TabbedPaneUIBasicTabbedPaneUI来编写您自己的MetalTabbedPaneUI来完成。但这很难写。

我相信你想实现类似关闭按钮(下面也适用于JLabel)

  • 我会尝试在GlassPane和图层
  • 上实现此按钮

  • (如果您的JDialog无法调整大小),您可setLayout(null)并提供组件位置和大小的硬编码值,并在JButton上添加JTabbedPane

  • 您可以覆盖内容窗格上的paintComponents并绘制自己的按钮(或由“假”JButton提供)。接下来 - 您必须在JTabbedPane上setMouseListener并检查鼠标单击位置是否在按钮的边界内。当然 - 您需要实现按钮可视状态(按下,悬停等)或只是将事件传递给faked JButton实例。