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

JComboBox doesn't resize in response to ListCellRenderer change.

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 1.4.0
    • 1.3.0
    • client-libs
    • beta
    • x86
    • windows_nt



      Name: sl110371 Date: 07/31/2000


      java version "1.3.0"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
      Java HotSpot(TM) Server VM (build 2.0fcs-E, mixed mode)

      JComboBox doesn't resize in response to ListCellRenderer change. The the
      underlying model changes, then the ComboBox will recompute its size, but if the
      renderer changes, it will not.

      In the sample program below, a ComboBox is used in a layout to get its preferred
      width. A renderer is used to display the models contents in upper case, or
      lower case. When the renderer is changed, at the next repaint, the ComboBox
      displays the correct format. However, it maintains its old size. If you
      'nudge' the ComboBox (by modifying the underlying model), then the ComboBox will
      resize itself in response to the new renderer.

      In the program, the JLabel at the top of the window displays the ComboBox's
      preferred size. The first button on the left toggle's the ComboBox's renderer
      between upper and lower. The next button on the left will 'nudge' the CombBox,
      and force it to recompute its size.

      The program takes one boolean parameter (which defaults to false). This
      specifies whether or not only one renderer should be used. When only one
      renderer is used, toggling the upper/lower effects the renderer, but the
      ComboBox doesn't get a 'setRenderer' invocation.

      I'm not suprised that the ComboBox does not resize when only one renderer is
      used, but I think it should when I explicitly change the renderer. It would be
      nice if the ComboBox would resize when its renderer implicitly changes though.
      Perhaps it could respond to a property change event, or have an explicit method
      requesting its size be recomputing (something like 'revalidate', though
      'revalidate' doesn't work in this instance).

      The sample program shows the bug at its worst when the first item is selected
      and is displayed in lowercase, and the ComboBox has been 'nudged.' Then when
      you change the renderer to upper case, only the first part of the item is
      displayed, followed by ellipsis.

        From reading BasicComboBoxUI, it seems that the ComboBox will be resized if the
      font property changes, the model property changes, or if the model is modified.
      It seems inconsistent that it won't be resized when the renderer changes (since
      the renderer seems to be just as vital to a 'correct' size as the font or the
      model).

      ================================================================================
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import javax.swing.event.*;

      public class Combo extends JPanel {

      static final String UP_STR = "Upper Case";
      static final String LO_STR = "Lower Case";

      public Combo(boolean pUseOne) {
      final boolean _useOneRenderer = pUseOne;
      final ToStringIfc _toUp = new ToUpper();
      final ToStringIfc _toLo = new ToLower();
      final StringRenderer _rendUp;
      final StringRenderer _rendLo;
      final JComboBox _box = new JComboBox
      (new Object[] { "LLLLLLLL", "First", "Second", "Third",
      "Fourth" });
      final JLabel _msg = new JLabel();

      ListCellRenderer _impl = _box.getRenderer();
      _rendUp = new StringRenderer(_impl, _toUp);
      _rendLo = new StringRenderer(_impl, _toLo);
      _box.setRenderer(_rendUp);
      _msg.setText(_box.getPreferredSize().toString());

      final JButton _toggleBtn = new JButton(LO_STR);
      ActionListener _toggle = new ActionListener() {
      public void actionPerformed(ActionEvent pAE) {
      boolean _isUp =
      _toggleBtn.getText().equals(UP_STR);
      _toggleBtn.setText(_isUp ? LO_STR : UP_STR);
      if (_useOneRenderer) {

      ((StringRenderer)_box.getRenderer()).setToString
      (_isUp ? _toUp : _toLo);
      } else {
      _box.setRenderer(_isUp ? _rendUp :
      _rendLo);
      }

      _msg.setText(_box.getPreferredSize().toString());
      }
      };
      _toggleBtn.addActionListener(_toggle);

      final JButton _nudgeBtn = new JButton("Nudge");
      ActionListener _nudge = new ActionListener() {
      public void actionPerformed(ActionEvent pAE) {
      _box.addItem(null);
      _box.removeItem(null);

      _msg.setText(_box.getPreferredSize().toString());
      }
      };
      _nudgeBtn.addActionListener(_nudge);

      JPanel _left = new JPanel();
      _left.setLayout(new BoxLayout(_left, BoxLayout.Y_AXIS));
      _left.add(_toggleBtn);
      _left.add(_nudgeBtn);

      JPanel _right = new JPanel();
      _right.setLayout(new BoxLayout(_right, BoxLayout.X_AXIS));
      _right.add(_box);

      setLayout(new BorderLayout());
      add(_msg, BorderLayout.NORTH);
      add(_left, BorderLayout.WEST);
      add(_right, BorderLayout.EAST);
      }

      public static void main(String[] pArgs) {
      boolean _useOne = false;
      try {
      _useOne = Boolean.valueOf(pArgs[0]).booleanValue();
      } catch (Exception _e) { }

      JFrame _frame = new JFrame
      (_useOne ? "One changing renderer" : "Two different
      renderers");

      _frame.setContentPane(new Combo(_useOne));
      _frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent pWE) {
      System.exit(0);
      } } );
      _frame.pack();
      _frame.setVisible(true);
      }
      }

      interface ToStringIfc {
      public String toString(Object pO);
      }

      class ToUpper implements ToStringIfc {
      public String toString(Object pO) {
      return String.valueOf(pO).toUpperCase();
      }
      }

      class ToLower implements ToStringIfc {
      public String toString(Object pO) {
      return String.valueOf(pO).toLowerCase();
      }
      }

      class StringRenderer implements ListCellRenderer {
      ListCellRenderer impl;
      ToStringIfc ifc;
      public StringRenderer(ListCellRenderer pImpl, ToStringIfc pToString) {
      impl = pImpl;
      setToString(pToString);
      }
      public void setToString(ToStringIfc pToString) {
      ifc = pToString;
      }
      public Component getListCellRendererComponent
      (JList pList,
      Object pValue,
      int pIndex,
      boolean pIsSelected,
      boolean pCellHasFocus) {

      return impl.getListCellRendererComponent
      (pList, ifc.toString(pValue), pIndex, pIsSelected,
      pCellHasFocus);
      }
      }
      (Review ID: 107761)
      ======================================================================

            mdavidsosunw Mark Davidson (Inactive)
            duke J. Duke
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: