6 Replies Latest reply: Sep 24, 2011 2:13 AM by yccheok RSS

    Combo box popup width adjusting no longer work in 1.0.6_26-b03

    yccheok
      Previously, I was able to adjusting combo box popup's width, by referring to the technique described in [http://tips4java.wordpress.com/2010/11/28/combo-box-popup/|http://tips4java.wordpress.com/2010/11/28/combo-box-popup/]. During that time, I was using 1.0.6_24-b07.

      However, after I update my Java runtime to 1.0.6_26-b03, things broke.

      Here is the screen shoot.

      [Workable screen shoot|http://i.imgur.com/0elo7.png]
      [Not workable screen shoot|http://i.imgur.com/BeKMy.png]

      Here is the code snippet to demonstrate this problem.
      /*
       * To change this template, choose Tools | Templates
       * and open the template in the editor.
       */
      
      /*
       * NewJFrame.java
       *
       * Created on Aug 9, 2011, 4:13:41 AM
       */
      
      package experiment;
      
      import java.awt.Component;
      import java.awt.Container;
      import java.awt.Dimension;
      import javax.swing.JComboBox;
      import javax.swing.JList;
      import javax.swing.JScrollBar;
      import javax.swing.JScrollPane;
      import javax.swing.SwingUtilities;
      import javax.swing.event.PopupMenuEvent;
      import javax.swing.event.PopupMenuListener;
      import javax.swing.plaf.basic.BasicComboPopup;
      
      /**
       *
       * @author yccheok
       */
      public class NewJFrame extends javax.swing.JFrame {
          /**
           * Adjust popup for combo box, so that horizontal scrollbar will not display.
           * Resize JComboBox dropdown doesn't work without customized ListCellRenderer
           * http://www.camick.com/java/source/BoundsPopupMenuListener.java
           *
           * @param comboBox The combo box
           */
          public static void adjustPopupWidth(JComboBox comboBox) {
              if (comboBox.getItemCount() == 0) return;
              Object comp = comboBox.getAccessibleContext().getAccessibleChild(0);
              if (!(comp instanceof BasicComboPopup)) {
                  return;
              }
              BasicComboPopup popup = (BasicComboPopup)comp;
              JList list = popup.getList();
              JScrollPane scrollPane = getScrollPane(popup);
      
              // Just to be paranoid enough.
              if (list == null || scrollPane == null) {
                  return;
              }
      
              //  Determine the maximimum width to use:
              //  a) determine the popup preferred width
              //  b) ensure width is not less than the scroll pane width
              int popupWidth = list.getPreferredSize().width
                              + 5  // make sure horizontal scrollbar doesn't appear
                              + getScrollBarWidth(popup, scrollPane);
              Dimension scrollPaneSize = scrollPane.getPreferredSize();
              popupWidth = Math.max(popupWidth, scrollPaneSize.width);
      
              //  Adjust the width
              scrollPaneSize.width = popupWidth;
              scrollPane.setPreferredSize(scrollPaneSize);
              scrollPane.setMaximumSize(scrollPaneSize);
          }
      
          /*
           *  I can't find any property on the scrollBar to determine if it will be
           *  displayed or not so use brute force to determine this.
           */
          private static int getScrollBarWidth(BasicComboPopup popup, JScrollPane scrollPane) {
              int scrollBarWidth = 0;
              Component component = popup.getInvoker();
              if (component instanceof JComboBox) {
                  JComboBox comboBox = (JComboBox)component;
      
                  if (comboBox.getItemCount() > comboBox.getMaximumRowCount()) {
                      JScrollBar vertical = scrollPane.getVerticalScrollBar();
                      scrollBarWidth = vertical.getPreferredSize().width;
                  }
              }
              return scrollBarWidth;
          }
      
          /*
           *  Get the scroll pane used by the popup so its bounds can be adjusted
           */
          private static JScrollPane getScrollPane(BasicComboPopup popup) {
              JList list = popup.getList();
              Container c = SwingUtilities.getAncestorOfClass(JScrollPane.class, list);
              return (JScrollPane)c;
          }
      
          /** Creates new form NewJFrame */
          public NewJFrame() {
              initComponents();
              this.jComboBox1.addPopupMenuListener(getPopupMenuListener());
          }
      
          /** This method is called from within the constructor to
           * initialize the form.
           * WARNING: Do NOT modify this code. The content of this method is
           * always regenerated by the Form Editor.
           */
          @SuppressWarnings("unchecked")
          // <editor-fold defaultstate="collapsed" desc="Generated Code">
          private void initComponents() {
      
              jComboBox1 = new javax.swing.JComboBox();
      
              setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
      
              jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4", "This is a very long text. This is a very long text" }));
      
              javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
              getContentPane().setLayout(layout);
              layout.setHorizontalGroup(
                  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                  .addGroup(layout.createSequentialGroup()
                      .addGap(82, 82, 82)
                      .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE)
                      .addContainerGap(242, Short.MAX_VALUE))
              );
              layout.setVerticalGroup(
                  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                  .addGroup(layout.createSequentialGroup()
                      .addGap(34, 34, 34)
                      .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                      .addContainerGap(246, Short.MAX_VALUE))
              );
      
              pack();
          }// </editor-fold>
      
          /**
          * @param args the command line arguments
          */
          public static void main(String args[]) {
              java.awt.EventQueue.invokeLater(new Runnable() {
                  public void run() {
                      new NewJFrame().setVisible(true);
                  }
              });
          }
      
          private PopupMenuListener getPopupMenuListener() {
              return new PopupMenuListener() {
                  @Override
                  public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                      // We will have a much wider drop down list.
                      adjustPopupWidth(jComboBox1);
                  }
      
                  @Override
                  public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                  }
      
                  @Override
                  public void popupMenuCanceled(PopupMenuEvent e) {
                  }
              };
          }
      
          // Variables declaration - do not modify
          private javax.swing.JComboBox jComboBox1;
          // End of variables declaration
      
      }
        • 1. Re: Combo box popup width adjusting no longer work in 1.0.6_26-b03
          mKorbel
          just my curiosity about that, here are

          1/ 1.0.6_24 returns another PreferredSize as 1.0.6_26 (there are another bad news as about Serializable),

          2/ that's about JDK or JRE (However, after I update my Java runtime to 1.0.6_26-b03) or both together

          just questions ...

          info ... and sometime isn't possible to remove just 1.0.6_26 upd, (on WinXp, Win7) then required remove all installed JRE an reinstall expected ...
          • 2. Re: Combo box popup width adjusting no longer work in 1.0.6_26-b03
            800268
            6u25 changed when popupMenuWillBecomeVisible is called: it is now called before the list is created so you can add items in that method and still have the list size correctly.

            See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4743225

            So for your workaround: either it isn't needed anymore or you need to add an extra hierarchy listener to check when the list is actually added.
            • 3. Re: Combo box popup width adjusting no longer work in 1.0.6_26-b03
              yccheok
              I had came across another workaround as stated here.

              [http://www.jroller.com/santhosh/entry/make_jcombobox_popup_wide_enough|http://www.jroller.com/santhosh/entry/make_jcombobox_popup_wide_enough]

              The popup's is having enough width to show all items. However, it is not perfect still, as the width is little too much. I still can see some extra space at the tailing of the list.

              The workaround is as follow.
              import javax.swing.*; 
              import java.awt.*; 
              import java.util.Vector; 
               
              // got this workaround from the following bug: 
              //      http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4618607 
              public class WideComboBox extends JComboBox{ 
               
                  public WideComboBox() { 
                  } 
               
                  public WideComboBox(final Object items[]){ 
                      super(items); 
                  } 
               
                  public WideComboBox(Vector items) { 
                      super(items); 
                  } 
               
                  public WideComboBox(ComboBoxModel aModel) { 
                      super(aModel); 
                  } 
               
                  private boolean layingOut = false; 
               
                  public void doLayout(){ 
                      try{ 
                          layingOut = true; 
                          super.doLayout(); 
                      }finally{ 
                          layingOut = false; 
                      } 
                  } 
               
                  public Dimension getSize(){ 
                      Dimension dim = super.getSize(); 
                      if(!layingOut) 
                          dim.width = Math.max(dim.width, getPreferredSize().width); 
                      return dim; 
                  } 
              }
              • 4. Re: Combo box popup width adjusting no longer work in 1.0.6_26-b03
                yccheok
                I have the workaround published at

                [http://jstock.hg.sourceforge.net/hgweb/jstock/jstock/rev/a05d8904788f|http://jstock.hg.sourceforge.net/hgweb/jstock/jstock/rev/a05d8904788f]

                Not elegant. But it works for me.
                • 5. Re: Combo box popup width adjusting no longer work in 1.0.6_26-b03
                  Kleopatra
                  how ingenuiously dirty - and indeed working :-)

                  Thanks for sharing!
                  Jeanette
                  • 6. Re: Combo box popup width adjusting no longer work in 1.0.6_26-b03
                    yccheok
                    Note that, unfortunately, the workaround is not workable under Linux. Need to figure out why. I am only tested on Windows Vista. I am not sure about Mac yet.