2012-05-16 2 views
3

У меня есть этот JDialog с JTabbedPane:Добавить JLabel в заголовке JTabbedPane

enter image description here

Я просто хочу добавить JLabel в правой верхней области JTabbedPane, так что я могу стрелять некоторые события (например, закрыть JDialog). И я не хочу, чтобы это был JFrame.

PS: Я знаю, что это может быть дублировано, но ни один из ответов не дает мне решения.

+1

Смотри также этот возможный дубликат: [вкладка вкладки JTabbedPane добавляет кнопку, она может отображаться, но она не может щелкнуть] (http://stackoverflow.com/questions/9937927/jtabbedpanes-tab-area-add-a-button-it- может-дисплей, но-это косяк щелчок). – trashgod

ответ

8

Ну, на самом деле это позиционирование внутри JTabbedPane не поддерживается в Swing. Но вы всегда можете сделать уличную магию с макетами и слоями:

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 границ внутри макета, чтобы сделать некоторые боковой интервал и такое ...

+0

хороший код, [я бы использовал GlassPane] (http://stackoverflow.com/a/9734016/714968), а не ...., потому что в случае, если есть куча вкладок, вы можете по ошибке нажать, чтобы закрыть вместо Tab (s), скрытых под JLabel, GlassPane, чтобы потреблять MouseEvent +1 – mKorbel

+0

Ну, он собирался поставить там что-то вроде ярлыка диалога, поэтому нет смысла проходить через события. Plus GlassPane действительно потребляет события - его поведение зависит только от того, как вы его создадите. Вы всегда можете заменить метод «содержит» на «ложный» возврат в любом компоненте, чтобы сделать его «прозрачным» для событий мыши - нет необходимости создавать обходные пути с помощью GlassPane. GlassPane на самом деле хорош, чтобы отображать некоторые глобальные вещи, такие как всплывающие подсказки/всплывающие окна/анимация перетаскивания и такие вещи ... –

+0

Просто отлично, большое спасибо. –

3

Это можно сделать, написав свой собственный TabbedPaneUI, расширив BasicTabbedPaneUI или MetalTabbedPaneUI. Но это было бы трудно написать.

Я верю, что вы хотите сделать что-то вроде кнопки закрытия (ниже будет работать с JLabel а)

  • Я хотел бы попробовать реализовать эту кнопку на GlassPane и Layers

или

  • (если ваш JDialog не изменяет размер), вы можете setLayout(null) и указать жестко заданные значения для положения и размера компонентов и добавить JButton над JTabbedPane

или

  • вы можете переопределить paintComponents на вашей панели содержимого и нарисовать свою собственную кнопку (или предоставляется «поддельные» JButton). Далее - вы должны указать setMouseListener на JTabbedPane и проверить, находится ли указатель мыши в пределах кнопок. Конечно, вам нужно будет реализовать визуальное состояние кнопки (нажатие, наведение и т. Д.) Или просто передать событие в экземпляр JButton faked.
+0

Я бы предпочел GLASSPane +1 – mKorbel