我想创建一个只读组合框。用户不应该从弹出列表中选择另一个项目。这意味着弹出列表不应该打开或应该为空。
我看到以下解决方案:
设置仅包含一个项目(当前所选项目)的ComboBox模型,因此当用户单击箭头按钮时,会显示一个空列表。
添加PopupMenuListener
并在popupMenuWillBecomeVisible
隐藏菜单中。这有问题:我们必须在combo.hidePopup();
SwingUtilities.invokeLater()
空模型方法看起来有点笨重。第二种方法显示弹出列表只有几分之一秒,足够短以至于被注意到。这非常难看。
有第三种解决方案吗?
编辑:已实施解决方案:
我从splungebob实现了建议的方法,这是我的代码供将来参考:
private void makeComboReadonly() {
Component editorComponent = box.getEditor().getEditorComponent();
if (editorComponent instanceof JTextField) {
((JTextField) editorComponent).setEditable(false);
}
for (Component childComponent : box.getComponents()) {
if (childComponent instanceof AbstractButton) {
childComponent.setEnabled(false);
final MouseListener[] listeners = childComponent.getListeners(MouseListener.class);
for (MouseListener listener : listeners) {
childComponent.removeMouseListener(listener);
}
}
}
final MouseListener[] mouseListeners = box.getListeners(MouseListener.class);
for (MouseListener listener : mouseListeners) {
box.removeMouseListener(listener);
}
final KeyListener[] keyListeners = box.getListeners(KeyListener.class);
for (KeyListener keyListener : keyListeners) {
box.removeKeyListener(keyListener);
}
box.setFocusable(false);
//box.getActionMap().clear(); //no effect
//box.getInputMap().clear();
}
唯一的问题是Key-Event Alt-Down,即使我删除所有关键监听器并清除动作映射,它也会弹出弹出菜单。我通过使组合不可聚焦来规避这个问题。不理想但足够好( - :
答案 0 :(得分:7)
这实际上是一个关于Swing限制之一的好问题(并且长期以来一直困扰着我)。
当...(等待它)时,需要一个只读组合框...表单当前处于只读模式。请注意,来自用户elswhere的输入可能会在一瞬间将表单翻转为编辑模式,因此切换JComponents(例如使用JLabel)在视觉上是不可取的,IMO。另请注意,禁用的组合不会向用户传达与只读组合相同的信息:
setEnabled(false)
- >完全变灰了;组件不能与之互动;无论显示的数据是不相关,不能选择复制/粘贴。
setReadOnly(true)
- >组合的文本组件不变灰(但箭头是);组件不能与之互动;任何可能显示的数据 相关且可以被选中。
对此的理由是,Swing 以setEditable(boolean)
的形式为JTextComponents实现此功能。谢谢大家,但我也需要JComboBox,JCheckbox,JRadioButton等。我们不得不为这个缺失的API推出我们自己的版本。
另一个Swing gaffe(IHMO)是不一致的API。 JTextComponent.setEditable(boolean)
强制执行只读行为,而JComboBox.setEditable(boolean)
则不执行。
Arrrgh !!!
所以,问题。你得卷起袖子。对于可编辑的组合:
通过combo.getEditor().getEditorComponent()
获取组合编辑器组件。它是一个JTextField。投下它,然后拨打setEditable(false)
。这为您提供了组合的文本部分所需的功能和外观。
通过迭代组合的getComponents()来获取组合的箭头组件。它是您唯一能找到的AbstractButton。致电setEnabled(false)
。这仅用于外观。
查找组合附带的所有默认鼠标侦听器(如果您没有自己添加任何内容,则应该是所有鼠标侦听器)并从组合和箭头按钮中删除它们。
保留对这些侦听器和箭头按钮的引用,以防您在只读= false时将其切换回来。
或类似的东西。你的旅费可能会改变。
Cue kleopatra赞同SwingX,它可能已经内置了这个功能(我当然不知道,我只是在猜测)。
祝你好运。答案 1 :(得分:1)
重写:
@Override
public void showPopup()
{
//do nothing
}
应该这样做。
答案 2 :(得分:1)
splungebob提供了完美的解决方案。这是他的注释变成了代码,以便您可以抓住它并继续:
private void setJComboBoxReadOnly(JComboBox jcb)
{
JTextField jtf = (JTextField)jcb.getEditor().getEditorComponent();
jtf.setEditable(false);
MouseListener[] mls = jcb.getMouseListeners();
for (MouseListener listener : mls)
jcb.removeMouseListener(listener);
Component[] comps = jcb.getComponents();
for (Component c : comps)
{
if (c instanceof AbstractButton)
{
AbstractButton ab = (AbstractButton)c;
ab.setEnabled(false);
MouseListener[] mls2 = ab.getMouseListeners();
for (MouseListener listener : mls2)
ab.removeMouseListener(listener);
}
}
}
答案 3 :(得分:0)
简单地禁用 JComboBox有什么问题?
setEnabled(false);
答案 4 :(得分:0)
我有类似的要求。调用setEnabled(false)
会出现可怕的外观,用户无法浏览下拉列表。覆盖showPopup()
不起作用。尝试通过invokeLater侦听菜单打开然后关闭它会导致菜单闪烁,用户再次无法浏览菜单。
最后我做了这个(不是说它完美,但它完全符合我的要求):
import javax.swing.JComboBox;
public class ReadOnlyComboBox<E> extends JComboBox<E>
{
private static final long serialVersionUID = 5866761337995322114L;
public ReadOnlyComboBox()
{
this.setModel(new ReadOnlyComboBoxModel<E>());
}
public void setReadOnly(boolean readOnly)
{
((ReadOnlyComboBoxModel<E>)this.getModel()).setReadOnly(readOnly);
}
}
import javax.swing.DefaultComboBoxModel;
public class ReadOnlyComboBoxModel<E> extends DefaultComboBoxModel<E>
{
private static final long serialVersionUID = -1923833835224513983L;
private boolean readOnly;
@Override
public void setSelectedItem(Object anItem)
{
if(!readOnly)
super.setSelectedItem(anItem);
}
public void setReadOnly(boolean readOnly)
{
this.readOnly = readOnly;
}
}
如果需要,您需要在setReadOnly(false)
上调用ReadOnlyComboBox
,然后以编程方式设置所选项目,然后将其重新设置为停止用户进行选择。
请注意未经检查的强制转换,在我的小程序中对我来说不是问题,但是如果尝试使用任何其他类型的模型,应该覆盖setModel
方法来查找异常。< / p>
编辑:还要注意仍然会调用动作侦听器(选择不变)。