Java JCombobox 禁用项目选择(使组合只读)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23500183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JCombobox disable item selection (make combo readonly)
提问by morpheus05
I'd like to create a readonly combobox. The user should not be able to select another item from the popup list. That means that the popup list should not open or should be empty.
我想创建一个只读组合框。用户不应能够从弹出列表中选择另一个项目。这意味着弹出列表不应打开或应为空。
I see the following solutions:
我看到以下解决方案:
Set a ComboBox model with only one item (the current selected item) so when the user clicks on the arrow button, an empty list is presented.
Add a
PopupMenuListener
and in thepopupMenuWillBecomeVisible
hide the menu. This is problematic: We have to callcombo.hidePopup();
from within aSwingUtilities.invokeLater()
设置一个只有一个项目(当前选择的项目)的 ComboBox 模型,这样当用户点击箭头按钮时,就会显示一个空列表。
PopupMenuListener
在popupMenuWillBecomeVisible
隐藏菜单中添加和。这是有问题的:我们必须combo.hidePopup();
从内部调用SwingUtilities.invokeLater()
The empty model approach seems a little bit clunky. The second approach shows the popup list for a fraction of a second, short enough to be noticed. This is very ugly.
空模型方法似乎有点笨拙。第二种方法显示弹出列表几分之一秒,短到足以引起注意。这是非常丑陋的。
Is there a third solution?
有第三种解决方案吗?
EDIT: Implemented solution:
编辑:实施的解决方案:
I implemented the suggested method from splungebob and here is my code for future reference:
我实现了 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();
}
The only problem is the Key-Event Alt-Down which oppens the popup menu even if I remove all the key listeners and clear the action map. I circumvent this problem by making the combo non focusable. Not ideal but good enough (-:
唯一的问题是 Key-Event Alt-Down 会打开弹出菜单,即使我删除了所有键侦听器并清除了动作映射。我通过使组合不可聚焦来规避这个问题。不理想但足够好 (-:
采纳答案by splungebob
This is actually a good question about one of Swing's limitations (and has bugged me for a long time).
这实际上是关于 Swing 局限性之一的好问题(并且困扰了我很长时间)。
One would need a read-only combobox when... (wait for it)... the form is currently in read-only mode. Note that input from the user elswhere may flip the form into edit mode at a moment's notice, so switching JComponents (using a JLabel for instance) would not be visually desirable, IMO. Also note that a disabled combo does not convey the same information to a user as a read-only combo would:
当...(等待它)...表单当前处于只读模式时,需要一个只读组合框。请注意,来自用户 elswhere 的输入可能会立即将表单翻转到编辑模式,因此切换 JComponents(例如使用 JLabel)在视觉上是不可取的,IMO。另请注意,禁用的组合不会像只读组合那样向用户传达相同的信息:
setEnabled(false)
-> entirely grayed out; the component cannotbe interacted with; whatever data may be shown is notrelevant and cannotbe selected for Copy/Paste.
setEnabled(false)
-> 完全变灰;该组件不能与之交互;任何数据可被示出的是不相关的和不能被选择用于复制/粘贴。
setReadOnly(true)
-> text component of combo is notgrayed out (but the arrow is); the component cannotbe interacted with; whatever data may be shown isrelevant and canbe selected.
setReadOnly(true)
-> 组合的文本组件没有变灰(但箭头是);该组件不能与之交互;任何可能显示的数据都是相关的并且可以选择。
Justification for this is that Swing didimplement this for JTextComponents in the form of setEditable(boolean)
. Thanks guys for that, but I also need it for JComboBox, JCheckbox, JRadioButton, etc. We had to roll our own versions for this missing API.
这样做的理由是 Swing确实以setEditable(boolean)
. 谢谢大家,但我也需要它用于 JComboBox、JCheckbox、JRadioButton 等。我们不得不为这个缺失的 API 推出我们自己的版本。
Another Swing gaffe (IHMO) is the inconsistent API. JTextComponent.setEditable(boolean)
enforces a read-only behavior, whereas JComboBox.setEditable(boolean)
does not.
另一个 Swing 失误 (IHMO) 是不一致的 API。 JTextComponent.setEditable(boolean)
强制执行只读行为,而JComboBox.setEditable(boolean)
不会。
Arrrgh!!!
啊!!!
So, to the problem. You gotta roll up your sleeves a bit. For an editablecombo:
所以,问题来了。你得稍微挽起袖子。对于可编辑的组合:
Get the combo's editor component via
combo.getEditor().getEditorComponent()
. It's a JTextField. Cast it, and callsetEditable(false)
. This gives you both the functionality and appearance you want for the text portion of the combo.Get the combo's arrow component by iterating over getComponents() of the combo. It's the only AbstractButton you'll find. Call
setEnabled(false)
. This is for appearance only.Find all of the default mouse listeners that came with the combo (which should be all of them if you didn't add any yourself) and remove them from both the combo and the arrow button.
Keep a reference to these listeners and the arrow button in case you want to switch it back to when read-only = false.
通过 获取组合的编辑器组件
combo.getEditor().getEditorComponent()
。这是一个 JTextField。投射它,然后调用setEditable(false)
。这为您提供了组合文本部分所需的功能和外观。通过迭代组合的 getComponents() 获取组合的箭头组件。这是您能找到的唯一 AbstractButton。打电话
setEnabled(false)
。这仅用于外观。找到组合附带的所有默认鼠标侦听器(如果您自己没有添加,则应该是所有这些)并将它们从组合和箭头按钮中删除。
保留对这些侦听器和箭头按钮的引用,以防您想在 read-only = false 时将其切换回。
Or something like that. Your mileage may vary.
或类似的东西。你的旅费可能会改变。
Cue kleopatra with an endorsement for SwingX, which probably has this functionality already built-in (I don't know that for sure, I'm just guessing).
提示 kleopatra 认可 SwingX,它可能已经内置了此功能(我不确定,我只是猜测)。
Good luck.
祝你好运。
回答by DSquare
Overriding:
覆盖:
@Override
public void showPopup()
{
//do nothing
}
should do the trick.
应该做的伎俩。
回答by Durandal
Whats wrong with simply disablingthe JComboBox?
简单地禁用JComboBox有什么问题?
setEnabled(false);
回答by Duncan Macleod
I had a similar requirement. Calling setEnabled(false)
gives a horrible appearance and the user can't browse the drop down. Overriding showPopup()
doesn't work. Trying to listen for the menu opening and then close it via invokeLater causes the menu to flash, and again the user can't browse the menu.
我也有类似的需求。呼叫setEnabled(false)
给人一种可怕的外观,用户无法浏览下拉菜单。覆盖showPopup()
不起作用。尝试侦听菜单打开然后通过 invokeLater 关闭它会导致菜单闪烁,并且用户再次无法浏览菜单。
In the end I did this (not saying its perfect, but it does exactly what I wanted):
最后我做到了(不是说它完美,但它完全符合我的要求):
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;
}
}
You need to call setReadOnly(false)
on the ReadOnlyComboBox
before setting the selected item programmatically if needed, then set it back to stop the user making selections.
你需要调用setReadOnly(false)
上ReadOnlyComboBox
设置所选项目编程如果需要的话,然后将其设置回停止用户作出选择之前。
Do note the unchecked cast, wasn't an issue for me in my small program, but should probably override the setModel
method to chuck an exception if an attempt is made to use any other kind of model.
请注意未经检查的强制转换,在我的小程序中对我来说不是问题,但setModel
如果尝试使用任何其他类型的模型,可能应该覆盖该方法以抛出异常。
Edit: Also note that action listeners are still called (with the unchanged selection).
编辑:另请注意,仍会调用动作侦听器(选择不变)。