Override BasicComboBoxUI and lose Look and Feel
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10

Thread: Override BasicComboBoxUI and lose Look and Feel

  1. #1
    Join Date
    Mar 2010
    Posts
    6

    Question Override BasicComboBoxUI and lose Look and Feel

    I have a ScrollableComboBox class that basically allows me to horizontally scroll the list if the ComboBox is not wide enough. When I Use this class, the look and feel is different from a regular JComboBox.

    There is no border and the arrow is grayed out.

    Is there any way to maintain the look and feel of a regular ComboBox while still adding the horizontal scroll bar?

    Would appreciate some help with this.

    Thanks!


    import com.lgc.calcSharedLight.ui.object.ScrollableComboBox;

    import java.awt.*;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.awt.event.WindowListener;

    import javax.swing.*;

    public class ComboBox extends JFrame {

    String [] _items = {"Item Number One", "Item Number Two", "Item Number Three"};
    public ComboBox() {
    super("ComboBox");
    getContentPane().setLayout(new BorderLayout());

    JPanel mainPanel = new JPanel();
    BoxLayout mainLayout = new BoxLayout(mainPanel, BoxLayout.Y_AXIS);

    JLabel label1 = new JLabel("Normal ComboBox");
    JPanel label1Panel = new JPanel();
    JComboBox label1ComboBox = new JComboBox(_items);
    label1Panel.setLayout( new FlowLayout(FlowLayout.LEFT));
    label1Panel.add(label1);
    label1Panel.add(label1ComboBox);

    JLabel label2 = new JLabel("Scrolled ComboBox");
    JPanel label2Panel = new JPanel();
    ScrollableComboBox label2ComboBox = new ScrollableComboBox(_items);
    label2Panel.setLayout( new FlowLayout(FlowLayout.LEFT));
    label2Panel.add(label2);
    label2Panel.add(label2ComboBox);


    mainPanel.add(label1Panel);
    mainPanel.add(label2Panel);

    getContentPane().add(mainPanel);

    WindowListener wndCloser = new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
    System.exit(0);
    }
    };
    addWindowListener(wndCloser);

    // setResizable(false);
    pack();
    setVisible(true);
    }


    public static void main(String argv[]) {
    new ComboBox();
    }
    }



    import javax.swing.*;
    import javax.swing.plaf.basic.BasicComboBoxUI;
    import javax.swing.plaf.basic.ComboPopup;
    import javax.swing.plaf.basic.BasicComboPopup;

    /**
    * When all text does not fit in ComboBox, scrollable comboBox is useful
    */
    public class ScrollableComboBox extends JComboBox{

    /**
    * Default Constructor
    * Empty ScrollableComboBox
    */
    public ScrollableComboBox()
    {
    super();
    setUI(new myComboUI());
    }

    /**
    * Populate ComboBox with array of items
    * @param items
    */
    public ScrollableComboBox(final Object items[])
    {
    super(items);
    setUI(new myComboUI());
    }


    public class myComboUI extends BasicComboBoxUI
    {
    protected ComboPopup createPopup()
    {
    BasicComboPopup popup = new BasicComboPopup(comboBox)
    {
    protected JScrollPane createScroller()
    {
    return new JScrollPane( list, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
    ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED );
    }
    };
    return popup;
    }
    }

  2. #2
    dlorde is offline Elite Member Power Poster
    Join Date
    Aug 1999
    Location
    UK
    Posts
    10,163

    Re: Override BasicComboBoxUI and lose Look and Feel

    Before getting into scrollable combo popups, did you consider just making the popup wide enough to display the full item text? It's much more user-friendly because they can see the full text without scrolling...

    Think twice, code once...
    Anon.
    Please use [CODE]...your code here...[/CODE] tags when posting code. If you get an error, please post the full error message and stack trace, if present.

  3. #3
    Join Date
    Mar 2010
    Posts
    6

    Re: Override BasicComboBoxUI and lose Look and Feel

    That would be an option, but for a number of reasons that is not the best solution to this case at this time. I do have a tool tip when items are selected which helps but would also like to mkake the scrollable ComboBox work and look like the other ComboBoxes in the panel.

  4. #4
    dlorde is offline Elite Member Power Poster
    Join Date
    Aug 1999
    Location
    UK
    Posts
    10,163

    Re: Override BasicComboBoxUI and lose Look and Feel

    What reasons?

    The cheapest, fastest, and most reliable components of a computer system are those that aren't there...
    G. Bell
    Please use [CODE]...your code here...[/CODE] tags when posting code. If you get an error, please post the full error message and stack trace, if present.

  5. #5
    Join Date
    Mar 2010
    Posts
    6

    Re: Override BasicComboBoxUI and lose Look and Feel

    I could redesign the entire gui of the application and fix this a different way. That is not what I am looking for right now. This is a wide dialog box with two side by side panels and many ComboBoxes. Most are not that wide but one can have up to 50 chars in it which would really make the dialog too wide.

    There were some bad design decisions that were made that I don't really want to get into, but changing everything right now just to accomodate this is not an option.

    Do you know if there is a way to do what I am trying to achieve?

  6. #6
    dlorde is offline Elite Member Power Poster
    Join Date
    Aug 1999
    Location
    UK
    Posts
    10,163

    Re: Override BasicComboBoxUI and lose Look and Feel

    Quote Originally Posted by houtex View Post
    ...This is a wide dialog box with two side by side panels and many ComboBoxes. Most are not that wide but one can have up to 50 chars in it which would really make the dialog too wide.
    I wasn't suggesting making the combo boxes themselves wider, but making the combo popup wider. The reason I'm focusing on this is because I recently had a similar problem - an application full of dialogs and popup windows containing tables, all with combo boxes in them, and many with columns too narrow or not enough space to display the full text of the items. I looked at scrolling popups, but they were difficult to implement, user unfriendly, and messed up our custom keyboard navigation.

    Here is an (admittedly extreme) example of a narrow combo box with a popup that sizes to the width of the widest item (not visible here):



    In all other respects, it behaves just like a normal combo box (ignore the custom border colours & stuff). If this would suit your requirements, I can show you how it's done.

    Plan to throw one away; you will anyhow...
    F. Brooks
    Please use [CODE]...your code here...[/CODE] tags when posting code. If you get an error, please post the full error message and stack trace, if present.

  7. #7
    Join Date
    Mar 2010
    Posts
    6

    Re: Override BasicComboBoxUI and lose Look and Feel

    Yes that would be fantastic. Much better solution then the scrollable ComboBox.

  8. #8
    dlorde is offline Elite Member Power Poster
    Join Date
    Aug 1999
    Location
    UK
    Posts
    10,163

    Re: Override BasicComboBoxUI and lose Look and Feel

    OK, here it is. To keep things simple, only the combo box is subclassed. This means a small kludge is necessary but saves a lot of faffing around.

    Note that it recalculates the popup width every time it gets popped up, which might be slow for huge lists of items. You could tweak it to only calculate the popup width when a new item is added, and use the precalculated value in the getsize() method instead. Also, it uses a kludge value in the calculateOptimumPopupWidth() method to compensate for the popup insets that are subtracted from the width in the popup's caller method (BasicComboPopup.getPopupLocation()). You could use the actual popup inset values here, but you'd have to supply a custom UI to give you access to the popup, which isn't directly accessible from the combo box (who designed this thing?):
    Code:
    public class AutoComboBox extends JComboBox {
        private boolean layingOut;
        private boolean isAutoPopupWidth = true;
        private int popupWidth;
    
        public AutoComboBox(Vector items) {
            super(items);
        }
    
        public AutoComboBox(ArrayList items) {
            this(items.toArray());
        }
    
        public AutoComboBox(ComboBoxModel comboBoxModel) {
            super(comboBoxModel);
        }
    
        public AutoComboBox(Object[] items) {
            super(items);
        }
    
        /**
         * Overriden to handle the popup Size
         */
        public void doLayout() {
            try {
                layingOut = true;
                super.doLayout();
            }
            finally {
                layingOut = false;
            }
        }
    
        /**
         * Overriden to handle the popup Size
         */
        public Dimension getSize() {
            Dimension dim = super.getSize();
            if (!layingOut) {
                if (isAutoPopupWidth) {
                    popupWidth = getOptimumPopupWidth();
                }
                if (popupWidth != 0) {
                    dim.width = popupWidth;
                }
            }
            return dim;
        }
    
        // return the greater of the combo width and the optimum popup width.
        private int getOptimumPopupWidth() {
            return Math.max(super.getSize().width, calculateOptimumPopupWidth());
        }
    
        // Find the maximum item text width
        private int calculateOptimumPopupWidth() {
            int width = 0;
            FontMetrics fontMetrics = getFontMetrics(getFont());
            for (int i = 0; i < getItemCount(); i++) {
                String text = getItemAt(i).toString();
                width = Math.max(width, fontMetrics.stringWidth(text));
            }
            // kludge to allow for BasicComboPopup insets (default 1 left + 1 right) which are subtracted from the
            // returned width (see BasicComboPopup.getPopupLocation()).
            return width + 3;
        }
    
        /**
         * Set the popup width to be the optimum (as for setOptimumPopupWidth) before displaying it.
         *
         * @param autoPopupWidth true to set the optimum width, false for the default behaviour.
         */
        public void setAutoPopupWidth(boolean autoPopupWidth) {
            isAutoPopupWidth = autoPopupWidth;
            if (!autoPopupWidth) {
                popupWidth = 0;
            }
        }
    
        /**
         * Indicates whether the popup width is automatically optimised before display.
         *
         * @return true if the popup width is automatically optimised, false if not.
         */
        public boolean isAutoPopupWidth() {
            return isAutoPopupWidth;
        }
    }
    The problem is never how to get new, innovative thoughts into your mind, but how to get old ones out!
    D. Hock
    Please use &#91;CODE]...your code here...&#91;/CODE] tags when posting code. If you get an error, please post the full error message and stack trace, if present.

  9. #9
    Join Date
    Mar 2010
    Posts
    6

    Re: Override BasicComboBoxUI and lose Look and Feel

    That works great!!! Thanks so much.

  10. #10
    dlorde is offline Elite Member Power Poster
    Join Date
    Aug 1999
    Location
    UK
    Posts
    10,163

    Re: Override BasicComboBoxUI and lose Look and Feel

    Glad to help

    Vague and nebulous is the beginning of all things, but not their end...
    K. Gibran
    Please use &#91;CODE]...your code here...&#91;/CODE] tags when posting code. If you get an error, please post the full error message and stack trace, if present.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center