Question

I'm trying to understand how getListCellRendererComponent method works but I don't get it. I made a separate class that extends BasicComboBoxRenderer and I added a counter which is printed every time getListCellRendererComponent is called. I then run a test class with a main method that shows a frame with just a JComboBox that uses my custom renderer class. This combobox has 3 items in total and I've set setMaximumRowCount(2) so it only shows 2 of them.

  • When I first run the program and the frame with the combobox appears, the counter informs that getListCellRendererComponent is called 6 times.
  • When the frame looses focus (when I click on my desktop for example) the method executes 1 time.
  • When the frame regains focus (click back on my frame) the method executes 1 time.
  • When I click on the arrow button and the drop-down list appears for the FIRST time, counter says that the method executes 8 times.
  • When I click again on the arrow button and the list disappears, the method is called 1 time (this happens always).
  • When I click on the arrow button AFTER the first time, the method is called 5 times.
  • When I click on the scrollbar button to go up or down, the method executes 1 time.
  • When I move the cursor on a not-selected item of the list, the method executes 2 times and after a second 1 more time (this is the most absurd)
  • When I click on an item of the list the method executes 4 times.

At first I thought that this method will be executed as many times as the number of the items in the list (plus one more that appears on the combobox display area).

But I can only understand one or two cases from the above, for example when I click the scrollbar buttons and the method executes 1 time, probably because a new item is rendered. The rest of them seem insane...

Was it helpful?

Solution

I would expect no less then n + 1 iterations of the renderer to be called at any one time.

The component needs to

  1. Figure out the best size for the contents. This can be achieved by using a prototype value or, if none is specified, iterating through all the items to find the max bounds (thats 3 times)
  2. Render the selected item if one exists +1 times
  3. Render the list if the popup is visible +3 times
  4. Possibly look for a tooltip

= a possible 7 iterations

When losing focus, the component needs to render the selected item +1

When regaining focus, the component will try a render te selected item again +1

When the popup is displayed, see the first part

The second time probably indicates that the component has cached the result of the first popup action (it's possible that the component is invalidating its internal cache between focus events)

Each time you change the view of the scrollpane, it needs to render any items not previously shown on the screen, this is done for optimisation reasons (imagine a lst with 100s of items, rendering all of them is a waste of time, hence the inclusion of the prototype value)

Mouse actions can be triggering a series of different actions, mouse in, mouse out, mouse move. Most likly these are to do with the tooltip manager and component trying to determine if a tooltip is available

Try setting a prototype value & see if that changes the number of iterations when the component displays its popup

OTHER TIPS

  1. I think that you forgot to describe how and which Object(s) you create or re_create in the Renderer,

  2. you forgot to sent here your view about Renderer in the SSCCE form

  3. then everything is in the academic level and too hard to write something about your Renderer ...

  4. Renderer react to the every Mouse and Key events

  5. plain Renderer with output from all important methods to the System.out.println("yyyy")

.

import java.awt.Component;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

public class ComboBoxHoverOver {

    private JComboBox combo = new JComboBox();

    public ComboBoxHoverOver() {
        combo.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXX");
        combo.setRenderer(new ComboToolTipRenderer(combo));
        combo.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                System.out.println("itemStateChanged");
            }
        });
        combo.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("actionPerformed");
            }
        });
        combo.addItem("");
        combo.addItem("Long text 4");
        combo.addItem("Long text 3");
        combo.addItem("Long text 2");
        combo.addItem("Long text 1");
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(combo);
        f.pack();
        f.setVisible(true);
    }

    private class ComboToolTipRenderer extends BasicComboBoxRenderer {

        private static final long serialVersionUID = 1L;
        private JComboBox combo;
        private JList comboList;

        ComboToolTipRenderer(JComboBox combo) {
            this.combo = combo;
        }

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            System.out.println(value + ", " + index + ", " + isSelected + ", " + cellHasFocus);
            if (comboList == null) {
                comboList = list;
                KeyAdapter listener = new KeyAdapter() {

                    @Override
                    public void keyReleased(KeyEvent e) {
                        if (e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_UP) {
                            int x = 5;
                            int y = comboList.indexToLocation(comboList.getSelectedIndex()).y;
                            System.out.println("keyReleased " + comboList.getSelectedIndex());
                        }
                    }
                };
                combo.addKeyListener(listener);
                combo.getEditor().getEditorComponent().addKeyListener(listener);
                comboList.addListSelectionListener(new ListSelectionListener() {

                    public void valueChanged(ListSelectionEvent e) {
                        if (e.getValueIsAdjusting()) {
                            JList list = (JList) e.getSource();
                            int item = list.getSelectedIndex();
                            if (item > -1) {
                                String string = list.getSelectedValue().toString();
                                System.out.println("valueChanged " + list.getSelectedValue().toString());
                            }
                        }
                    }
                });
            }
            if (isSelected) {
                System.out.println("isSelected " + value.toString());
            }
            return this;
        }
    }

    public static void main(String[] args) {

        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ComboBoxHoverOver comboBoxHoverOver = new ComboBoxHoverOver();
            }
        });
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top