我试图理解getListCellRendererComponent方法是如何工作的,但我不明白。我创建了一个单独的类来扩展BasicComboBoxRenderer,并添加了一个计数器,每次调用getListCellRender Component时都会打印该计数器。然后,我用一个主方法运行一个测试类,该方法只显示了一个使用我的自定义渲染器类的JComboBox的框架。这个组合框总共有3个项目,我设置了setMaximumRowCount(2),所以它只显示其中的2个。
- 当我第一次运行程序时,出现了带有组合框的帧,计数器通知getListCellRendererComponent被调用了6次
- 当框架失去焦点时(例如,当我点击桌面时),该方法执行1次
- 当帧重新获得焦点时(单击我的帧),该方法执行1次
- 当我点击箭头按钮,下拉列表第一次出现时,计数器显示该方法执行8次
- 当我再次单击箭头按钮,列表消失时,该方法被调用1次(这种情况总是发生)
- 当我第一次点击AFTER箭头按钮时,该方法被调用了5次
- 当我点击滚动条按钮向上或向下时,该方法执行1次
- 当我将光标移动到列表中未选择的项目上时,该方法执行2次,然后再执行1次(这是最荒谬的)
- 当我点击列表中的一个项目时,该方法会执行4次
起初,我认为这个方法的执行次数与列表中项目的数量一样多(再加上组合框显示区域上出现的一个)。
但我只能理解上面的一两种情况,例如,当我单击滚动条按钮,该方法执行1次时,可能是因为渲染了一个新项目。他们其他人看起来都疯了。。。
我希望在任何时候都能调用不少于n+1次渲染器迭代。
组件需要
- 找出内容的最佳大小。这可以通过使用原型值来实现,或者,如果没有指定,则遍历所有项以找到最大边界(即3次)
- 渲染选定项目(如果存在)+1次
- 如果弹出窗口可见,则渲染列表+3次
- 可能查找工具提示
=可能的7次迭代
失去焦点时,组件需要渲染所选项目+1
当重新获得焦点时,组件将再次尝试渲染所选项目+1
显示弹出窗口时,请参阅第一部分
第二次可能表示组件缓存了第一次弹出操作的结果(可能是组件在焦点事件之间使其内部缓存无效)
每次更改滚动窗格的视图时,它都需要渲染屏幕上以前未显示的任何项目,这是出于优化原因(想象一个有100个项目的lst,渲染所有项目都是浪费时间,因此包含原型值)
鼠标动作可以触发一系列不同的动作,鼠标进、鼠标出、鼠标移动。最常见的是工具提示管理器和组件试图确定工具提示是否可用
尝试设置一个原型值&看看当组件显示其弹出时,这是否会改变迭代次数
-
我认为您忘记描述如何以及在
Renderer
、中创建或重新创建哪个Object(s)
-
你忘了在SSCCE表格中发送你对
Renderer
的看法 -
那么一切都处于学术水平,很难写一些关于你的
Renderer
的东西。。。 -
Renderer
对每个Mouse
和Key
事件作出反应 -
普通
Renderer
,从所有重要方法输出到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();
}
});
}
}