JDK-4743225 : Size of JComboBox list is wrong when list is populated via PopupMenuListener
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.1,6,6u3,6u10,6u20
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: linux,windows_xp
  • CPU: x86
  • Submitted: 2002-09-06
  • Updated: 2010-10-26
  • Resolved: 2011-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7
6u22-revFixed 7 b105Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Name: jk109818			Date: 09/06/2002


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

FULL OPERATING SYSTEM VERSION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
I'm exploiting the new capability in JDK 1.4 to add a
PopupMenuListener to a JComboBox to populate the list just
before it is shown.  When I click on the combo box to open
the popup list, the contents of the popup list looks fine,
but the size of the list is wrong.  The size of the list is
apparently calculated from the previous number of entries in
the combo box model.  It should use the new count of entries
instead.  To get the popup list to size correctly, you must
close the popup list and open it again.

I reported this problem once before on 6/17/2002.  It was
assigned an internal review ID of 153748.  But I haven't
seen any further progress, and the bug doesn't show up in
the bug database, so I'm submitting it again.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the provided demonstration program.
2. Click on the arrow to open the popup list for the combo box.
3. Observe that the list is sized to show three items, which
is the OLD size of the list.
4. Close the popup list and open it again to observe that
the list is now sized for 8 items, the default maximum list
size.

EXPECTED VERSUS ACTUAL BEHAVIOR :
When opening the combo box, it is sized for 3 items, but the
list really contains 10 items.  It should size the list for
8 items, the default maximum list size.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.BorderLayout;
import javax.swing.*;
import javax.swing.event.*;

class ComboBug extends AbstractListModel implements ComboBoxModel,
PopupMenuListener {
   JFrame f;
   Object selected;
   Object[] items;

   public static void main(String[] args) {
      new ComboBug();
   }

   ComboBug() {
      f = new JFrame("Combo demo");
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      items = new Object[] {"First", "Second", "Third"};
      setSelectedItem(items[0]);

      JComboBox combo = new JComboBox(this);
      combo.addPopupMenuListener(this);
      f.getContentPane().add(combo, BorderLayout.CENTER);
      f.pack();
      f.show();
   }

   public int getSize() {
      return items.length;
   }

   public Object getElementAt(int index) {
      return items[index];
   }

   public void setSelectedItem(Object obj) {
      selected = obj;
      fireContentsChanged(this, -1, -1); // Same as what DefaultComboBoxModel fires
   }

   public Object getSelectedItem() {
      return selected;
   }

   public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
      int oldSize = items.length;
      items = new Object[] {"One", "Two", "Three", "Four", "Five", "Six",
"Seven", "Eight", "Nine", "Ten"};
      fireIntervalRemoved(this, 0, oldSize - 1);
      fireIntervalAdded(this, 0, items.length - 1);
      setSelectedItem(items[0]);
   }

   public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
   public void popupMenuCanceled(PopupMenuEvent e) {}
}

---------- END SOURCE ----------
(Review ID: 164152) 
======================================================================

Comments
WORK AROUND public void popupMenuWillBecomeVisible(PopupMenuEvent ev) { if(!willBecomeVisble){ JComboBox list = (JComboBox)ev.getSource(); .... // make some changes on the data model willBecomeVisble = true; // the flag is needed to prevent a loop try{ list.getUI().setPopupVisible( list, true ); }finally{ willBecomeVisble = false; } } }
26-10-2006

EVALUATION Contribution-Forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?messageID=12475&forumID=1463
05-04-2006

EVALUATION There are two fixes offered http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4743225 I tried one Submitted On 18-FEB-2006 it doesn't fix the test case in description The fix Submitted On 25-MAR-2004 fixes it, but it is a real hack it just quickly shows and hides the combobox's popup first it might lead to popup blinking second it uses awt.Robot which is designed for regression tests only ComboBox popup doesn't expect to be updated in popupMenuWillBecomeVisible() method, before showing on the screen we calculate the popup size and location first then we call popupMenuWillBecomeVisible() and PopupMenuListener's and then we show the popup actually we should have documented this behaviour when PopupMenuListener appears The complete design is difficult and risky to be changed, I don't think we can change in backward compatible manner now We'll back to this issue after Mustang
22-03-2006

WORK AROUND Subclass BasicComboPopup and implement createScroller() to return a custom JScrollPane subclass that implements getPreferredSize. Not an easy solution.
02-10-2004

SUGGESTED FIX ------- BasicComboPopup.java ------- 512,514c512 < return new JScrollPane( list, < ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, < ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER ); --- > return new PopupScrollPane(); 516a515,537 > // Fix for 4743225 > class PopupScrollPane extends JScrollPane { > > public PopupScrollPane() { > super(list, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, > ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER ); > } > > public Dimension getPreferredSize() { > Dimension popupSize = comboBox.getSize(); > Insets insets = getInsets(); > > // reduce the width of the scrollpane by the insets so that the popup > // is the same width as the combo box. > popupSize.setSize(popupSize.width - (insets.right + insets.left), > getPopupHeightForRowCount( comboBox.getMaximumRowCount())); > Rectangle popupBounds = computePopupBounds( 0, comboBox.getBounds().height, > popupSize.width, popupSize.height); > return popupBounds.getSize(); > } > } > > 1091d1111 < Dimension scrollSize = popupBounds.getSize(); 1093a1114,1115 > /* > Dimension scrollSize = popupBounds.getSize(); 1096c1118 < scroller.setMinimumSize( scrollSize ); --- > scroller.setMinimumSize( scrollSize ); */
02-10-2004

EVALUATION The fundamental problem is that the size of the popup portion of the combo box has been computed by the time the firePopupMenuWillBecomeVisible. The sequence of events for computing the bounds and showing the popup is as follows: BasicComboPopup.show() -> getPopupLocation - Compute the size of the list (component added to popup) ->getPopupHeightForRowCount() - Height of popup made here. ->JPopupMenu.show(...); ->setVisible(true); ->firePopupMenuWillBecomeVisible() - Notification of popup. ->getPopup() ->adjustPopupLocationToFitScreen ->size = JPopupMenu.this.getPreferredSize(); The solution could be to create a custom subclass of JScrollBar for BasicComboPopup which would implement the getPreferredSize method to compute the preferred size base on the getPopupHeightForRowCount(). This would be a good idea since size calcultions should be done in getPreferredSize, etc... as much as possible. ###@###.### 2002-09-06
06-09-2002