2012-03-09 10 views
4

タブの幅がタブ付きペインの幅を超えると、タブが無制限のJTabbedPaneを持つアプリケーションでは、タブが複数の行に折り返されます。上の行のいずれかのタブをクリックすると、完全な行がフォアグラウンドになります。いくつかのタブの間をクリックするユーザーにとっては、タブの順序を把握することができないため、非常に混乱します。 (私は気にしませんが、タブのメタファーこの場合と光学的に破損しているが)前にその内容をもたらしながら、固定位置にタブを爪、または - -JTabbedPaneまたは1つの行の固定位置にあるタブ

私はどちらか するにはどうすればよい

1に行の数を制限します(タブはラッピングの代わりに非常に狭くなります)?

+0

別のタイプのコントロールに切り替えるのはどうですか?リストやツリーのように? – Randy

+0

'setTabLayoutPolicy()'はあなたが探しているものかもしれません –

+0

@Guillaume、setTabLayoutPolicy()にはスクロールまたはラップの2つの値しかありません。 – micro

答えて

3

本当に迅速かつ汚い(間違いなく改善や変更を必要とする)が、私はそのような何かがあなたのために仕事ができることを想像(しかしJTabbePaneではありません):

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.Container; 
import java.awt.Dimension; 
import java.awt.FlowLayout; 
import java.awt.Insets; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.SwingUtilities; 

public class Test { 

    /** 
    * FlowLayout subclass that fully supports wrapping of components. 
    */ 
    public static class WrapLayout extends FlowLayout { 
     private Dimension preferredLayoutSize; 

     /** 
     * Constructs a new <code>WrapLayout</code> with a left alignment and a 
     * default 5-unit horizontal and vertical gap. 
     */ 
     public WrapLayout() { 
      super(); 
     } 

     /** 
     * Constructs a new <code>FlowLayout</code> with the specified alignment 
     * and a default 5-unit horizontal and vertical gap. The value of the 
     * alignment argument must be one of <code>WrapLayout</code>, 
     * <code>WrapLayout</code>, or <code>WrapLayout</code>. 
     * 
     * @param align 
     *   the alignment value 
     */ 
     public WrapLayout(int align) { 
      super(align); 
     } 

     /** 
     * Creates a new flow layout manager with the indicated alignment and 
     * the indicated horizontal and vertical gaps. 
     * <p> 
     * The value of the alignment argument must be one of 
     * <code>WrapLayout</code>, <code>WrapLayout</code>, or 
     * <code>WrapLayout</code>. 
     * 
     * @param align 
     *   the alignment value 
     * @param hgap 
     *   the horizontal gap between components 
     * @param vgap 
     *   the vertical gap between components 
     */ 
     public WrapLayout(int align, int hgap, int vgap) { 
      super(align, hgap, vgap); 
     } 

     /** 
     * Returns the preferred dimensions for this layout given the 
     * <i>visible</i> components in the specified target container. 
     * 
     * @param target 
     *   the component which needs to be laid out 
     * @return the preferred dimensions to lay out the subcomponents of the 
     *   specified container 
     */ 
     @Override 
     public Dimension preferredLayoutSize(Container target) { 
      return layoutSize(target, true); 
     } 

     /** 
     * Returns the minimum dimensions needed to layout the <i>visible</i> 
     * components contained in the specified target container. 
     * 
     * @param target 
     *   the component which needs to be laid out 
     * @return the minimum dimensions to lay out the subcomponents of the 
     *   specified container 
     */ 
     @Override 
     public Dimension minimumLayoutSize(Container target) { 
      Dimension minimum = layoutSize(target, false); 
      minimum.width -= getHgap() + 1; 
      return minimum; 
     } 

     /** 
     * Returns the minimum or preferred dimension needed to layout the 
     * target container. 
     * 
     * @param target 
     *   target to get layout size for 
     * @param preferred 
     *   should preferred size be calculated 
     * @return the dimension to layout the target container 
     */ 
     private Dimension layoutSize(Container target, boolean preferred) { 
      synchronized (target.getTreeLock()) { 
       // Each row must fit with the width allocated to the containter. 
       // When the container width = 0, the preferred width of the 
       // container 
       // has not yet been calculated so lets ask for the maximum. 

       int targetWidth = target.getSize().width; 

       if (targetWidth == 0) { 
        targetWidth = Integer.MAX_VALUE; 
       } 

       int hgap = getHgap(); 
       int vgap = getVgap(); 
       Insets insets = target.getInsets(); 
       int horizontalInsetsAndGap = insets.left + insets.right + hgap * 2; 
       int maxWidth = targetWidth - horizontalInsetsAndGap; 

       // Fit components into the allowed width 

       Dimension dim = new Dimension(0, 0); 
       int rowWidth = 0; 
       int rowHeight = 0; 

       int nmembers = target.getComponentCount(); 

       for (int i = 0; i < nmembers; i++) { 
        Component m = target.getComponent(i); 

        if (m.isVisible()) { 
         Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize(); 

         // Can't add the component to current row. Start a new 
         // row. 

         if (rowWidth + d.width > maxWidth) { 
          addRow(dim, rowWidth, rowHeight); 
          rowWidth = 0; 
          rowHeight = 0; 
         } 

         // Add a horizontal gap for all components after the 
         // first 

         if (rowWidth != 0) { 
          rowWidth += hgap; 
         } 

         rowWidth += d.width; 
         rowHeight = Math.max(rowHeight, d.height); 
        } 
       } 

       addRow(dim, rowWidth, rowHeight); 

       dim.width += horizontalInsetsAndGap; 
       dim.height += insets.top + insets.bottom + vgap * 2; 

       // When using a scroll pane or the DecoratedLookAndFeel we need 
       // to 
       // make sure the preferred size is less than the size of the 
       // target containter so shrinking the container size works 
       // correctly. Removing the horizontal gap is an easy way to do 
       // this. 

       Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target); 

       if (scrollPane != null) { 
        dim.width -= hgap + 1; 
       } 

       return dim; 
      } 
     } 

     /* 
     * A new row has been completed. Use the dimensions of this row 
     * to update the preferred size for the container. 
     * 
     * @param dim update the width and height when appropriate 
     * @param rowWidth the width of the row to add 
     * @param rowHeight the height of the row to add 
     */ 
     private void addRow(Dimension dim, int rowWidth, int rowHeight) { 
      dim.width = Math.max(dim.width, rowWidth); 

      if (dim.height > 0) { 
       dim.height += getVgap(); 
      } 

      dim.height += rowHeight; 
     } 
    } 

    public static class MyTabbedPane extends JPanel { 
     private JPanel buttonPanel; 
     private JPanel currentview; 

     private Tab currentTab; 

     private class Tab { 
      String name; 
      JComponent component; 
     } 

     private List<Tab> tabs = new ArrayList<Tab>(); 

     public MyTabbedPane() { 
      super(new BorderLayout()); 
      buttonPanel = new JPanel(new WrapLayout()); 
      currentview = new JPanel(); 
      add(buttonPanel, BorderLayout.NORTH); 
      add(currentview); 
     } 

     public void addTab(String name, JComponent tabView, int index) { 
      if (index < 0 || index > tabs.size()) { 
       throw new IllegalArgumentException("Index out of bounds"); 
      } 
      final Tab tab = new Tab(); 
      tab.component = tabView; 
      tab.name = name; 
      tabs.add(index, tab); 
      JButton b = new JButton(name); 
      b.addActionListener(new ActionListener() { 

       @Override 
       public void actionPerformed(ActionEvent e) { 
        setCurrentTab(tab); 
       } 

      }); 
      buttonPanel.add(b, index); 
      buttonPanel.validate(); 
     } 

     public void removeTab(int i) { 
      Tab tab = tabs.remove(i); 

      if (tab == currentTab) { 
       if (tabs.size() > 0) { 
        if (i < tabs.size()) { 
         setCurrentTab(tabs.get(i)); 
        } else { 
         setCurrentTab(tabs.get(i - 1)); 
        } 
       } else { 
        setCurrentTab(null); 
       } 
      } 
      buttonPanel.remove(index); 
     } 

     void setCurrentTab(final Tab tab) { 
      if (currentTab == tab) { 
       return; 
      } 
      if (currentTab != null) { 
       currentview.remove(currentTab.component); 
      } 
      if (tab != null) { 
       currentview.add(tab.component); 
      } 
      currentTab = tab; 
      currentview.validate(); 
     } 
    } 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     MyTabbedPane tabbedPane = new MyTabbedPane(); 
     for (int i = 0; i < 100; i++) { 
      tabbedPane.addTab("Button " + (i + 1), new JLabel("Dummy Label " + (i + 1)), i); 
     } 
     frame.add(tabbedPane); 
     frame.pack(); 
     frame.setSize(new Dimension(1000, 800)); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 

} 

WrapLayoutが別のポストから取りましたSO。

+0

+1 JScrollPaneでJButtonの束を見ました – mKorbel

+0

JTabbedPaneを簡単に変更する方法はないと思います。ありがとう! – micro

+0

本当に必要な場合は、JTabbedPaneを拡張し、JTabbedPaneのすべてのメソッドをオーバーライドして、それを上書きすることができます。 –