Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4879877

Problem in JTabbedPane's preferred size computation

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 5.0
    • 1.4.2
    • client-libs
    • tiger
    • x86
    • windows_nt



      Name: rmT116609 Date: 06/17/2003


      FULL PRODUCT VERSION :
      java version "1.4.2-beta"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-beta-b19)
      Java HotSpot(TM) Client VM (build 1.4.2-beta-b19, mixed mode)

      FULL OS VERSION :
      Windows NT Version 4.0

      A DESCRIPTION OF THE PROBLEM :
      The preferred size computed for a JTabbedPane does not always return the correct value. Sometimes it thinks the tabs fits on one row but when the layout is actually done, it fits on two rows. This causes the inside panels to be truncated. I analysed the source code in the BasicTabbedPaneUI and found that the tab area insets are not taken into account in the computation of the preferred size. The problem can be found in the following routines: BasicTabbedPaneUI.TabbedPaneLayout.preferredTabAreaHeight and BasicTabbedPaneUI.TabbedPaneLayout.preferredTabAreaWidth.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      See the sample code

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The preferred size of the JTabbedPane should include to size to fit two tab rows instead of just one.
      ACTUAL -
      The preferred size of the JTabbedPane includes to size to fit one row but when the JTabbedPane is painted it displays two tab rows, this causes the content of the tabbed panel to be truncated.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.BorderLayout;

      import javax.swing.*;

      /**
       * Test class to reproduce the bug with the computation of the JTabbedPane's preferred size.
       */
      public class TestJTabbedPane extends JPanel
      {
         private static final String TAB1_TITLE = "tab 1 title";
         private static final String TAB2_TITLE = "tab 2 title";
         private static final String TAB3_TITLE = "tab 3 title";
         
         private JTabbedPane tabbedPane = new JTabbedPane();
         private JPanel tab1Panel = new JPanel();
         private JPanel tab2Panel = new JPanel();
         private JPanel tab3Panel = new JPanel();
         
         public TestJTabbedPane( int aConfig )
         {
            setLayout( new BorderLayout() );
            if( aConfig == 0 )
            {
               tab2Panel.add( new JButton( "test button1" ) );
               tab2Panel.add( new JButton( "test button2" ) );
            }
            else
            {
               tab2Panel.add( new JButton( "test butto1" ) );
               tab2Panel.add( new JButton( "test butto2" ) );
            }
            
            tabbedPane.add( TAB1_TITLE, tab1Panel );
            tabbedPane.add( TAB2_TITLE, tab2Panel );
            tabbedPane.add( TAB3_TITLE, tab3Panel );
            add( tabbedPane, BorderLayout.CENTER );
         }
         
         public static void main(String[] args)
         {
            try
            {
               JFrame frame1 = new JFrame();
               frame1.setTitle( "Truncated tabbed panel content");
               frame1.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

               TestJTabbedPane panel1 = new TestJTabbedPane( 0 );
               frame1.getContentPane().add( panel1 );
               frame1.pack();
               System.out.println( "frame1 tabbed pane pref size: " + panel1.tabbedPane.getPreferredSize() );
               System.out.println( "frame1 tab2 pref size: " + panel1.tab2Panel.getPreferredSize() );
               System.out.println( "frame1 tabbed pane size: " + panel1.tabbedPane.getSize() );

               JFrame frame2 = new JFrame();
               frame2.setTitle( "Valid tabbed panel content");
               frame2.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

               TestJTabbedPane panel2 = new TestJTabbedPane( 1 );
               frame2.getContentPane().add( panel2 );
               frame2.pack();
               System.out.println( "frame2 tabbed pane pref size: " + panel2.tabbedPane.getPreferredSize() );
               System.out.println( "frame2 tab2 pref size: " + panel2.tab2Panel.getPreferredSize() );
               System.out.println( "frame2 tabbed pane size: " + panel2.tabbedPane.getSize() );

               frame1.show();
               frame2.show();
            }
            catch( Exception e )
            {
               e.printStackTrace();
            }
         }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      I have replaced the WindowsTabbedPaneUI by a copy of it with some modifications that fixes the bug in the computation of the preferredSize.

      public class ExtendedTabbedPaneUI extends WindowsTabbedPaneUI
      {
         // UI creation
         public static ComponentUI createUI(JComponent c)
         {
            return new ExtendedTabbedPaneUI();
         }

         // Documentation inherited from base class
         protected LayoutManager createLayoutManager()
         {
            if( tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
            {
               return super.createLayoutManager();
            }
            else
            { /* WRAP_TAB_LAYOUT */
                return new TabbedPaneLayout();
            }
         }

         /**
          * Overrides the <code>BasicTabbedPaneUI</code> layout manager to fix a bug in the computation
          * of the tabbed pane preferred size. The tab area insets was not taken into account.
          */
         public class TabbedPaneLayout extends WindowsTabbedPaneUI.TabbedPaneLayout
         {
            // Documentation inherited from base class
            protected int preferredTabAreaHeight( int aTabPlacement, int aWidth )
            {
               FontMetrics metrics = getFontMetrics();
               Insets tabAreaInsets = getTabAreaInsets( aTabPlacement );
               int tabCount = tabPane.getTabCount();
               int total = 0;
      // On the following I changed the width to take into account the tab area
      // insets, they are computed in the layout of the tabbed pane but not in the
      // computation of the preffered size
               int returnAt = aWidth - ( tabAreaInsets.left + tabAreaInsets.right );
               if( tabCount > 0 )
               {
                  int rows = 1;
                  int x = 0;

                  int maxTabHeight = calculateMaxTabHeight(aTabPlacement);

                  for( int i = 0; i < tabCount; i++ )
                  {
                     int tabWidth = calculateTabWidth( aTabPlacement, i, metrics );

                     if( x != 0 && ( x + tabWidth ) > returnAt )
                     {
                        rows++;
                        x = 0;
                     }
                     x += tabWidth;
                  }
                  total = calculateTabAreaHeight( aTabPlacement, rows, maxTabHeight );
               }
               return total;
            }

            // Documentation inherited from base class
            protected int preferredTabAreaWidth(int aTabPlacement, int aHeight )
            {
               FontMetrics metrics = getFontMetrics();
               Insets tabAreaInsets = getTabAreaInsets( aTabPlacement );
               int tabCount = tabPane.getTabCount();
               int total = 0;
      // On the following I changed the height to take into account the tab area
      // insets, they are computed in the layout of the tabbed pane but not in the
      // computation of the preffered size
               int returnAt = aHeight - ( tabAreaInsets.top + tabAreaInsets.bottom );
               if( tabCount > 0 )
               {
                  int columns = 1;
                  int y = 0;
                  int fontHeight = metrics.getHeight();

                  maxTabWidth = calculateMaxTabWidth( aTabPlacement );

                  for( int i = 0; i < tabCount; i++ )
                  {
                     int tabHeight = calculateTabHeight( aTabPlacement, i, fontHeight );

                     if( y != 0 && ( y + tabHeight ) > returnAt )
                     {
                        columns++;
                        y = 0;
                     }
                     y += tabHeight;
                  }
                  total = calculateTabAreaWidth( aTabPlacement, columns, maxTabWidth );
               }
               return total;
            }
         }
      }
      (Review ID: 188357)
      ======================================================================

            moasunw Moa Moa (Inactive)
            rmandalasunw Ranjith Mandala (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: