Java 具有可编辑JComboxes的奇怪选项卡顺序
我有一个Java 具有可编辑JComboxes的奇怪选项卡顺序,java,swing,focus,jcombobox,Java,Swing,Focus,Jcombobox,我有一个JFrame看起来像这样: 它有两个JTextFields,一个JComboBox在它们之间,一个JPanel在底部(你看不到) JComboBox的一个特性是可以为它提供一个自定义编辑器。它们实现了ComboBoxEditor接口。在以下三种情况中,GUI看起来都完全相同,我希望它们的行为都完全相同: 我没有指定自定义编辑器,而是使用默认编辑器 我创建了一个自定义编辑器,其编辑器组件是JTextField 我创建了一个自定义编辑器,其编辑器组件是一个JPanel,上面有一个JTex
JFrame
看起来像这样:
它有两个JTextField
s,一个JComboBox
在它们之间,一个JPanel
在底部(你看不到)
JComboBox
的一个特性是可以为它提供一个自定义编辑器。它们实现了ComboBoxEditor
接口。在以下三种情况中,GUI看起来都完全相同,我希望它们的行为都完全相同:
- 我没有指定自定义编辑器,而是使用默认编辑器李>
- 我创建了一个自定义编辑器,其编辑器组件是
JTextField
- 我创建了一个自定义编辑器,其编辑器组件是一个
,上面有一个JPanel
(使用JTextField
)李>BorderLayout
JTextField
移动到JComboBox
上的编辑区域,然后移动到另一个JTextField
。如果我创建了一个自定义编辑器,它的编辑器组件是JTextField
,如果我不这样做,同样的事情也会发生
但是,如果我创建了一个自定义编辑器,其编辑器组件是一个JPanel
,其中有一个JTextField
ed,那么焦点会额外停止一次。如果焦点位于顶部JTextField
,则按Tab键将焦点移动到可编辑组合框右侧的小箭头,然后再移动到文本区域
为什么会这样?焦点永远不会移到帧底部的JPanel
,那么为什么按住JTextField
的JPanel
会影响组合框上的选项卡顺序
以下是一个S(-ish)SCCE,其中有一个文本字段和所有三种类型的组合框:
import javax.swing.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
public class ComboBoxTest extends JFrame
{
private JPanel layoutPanel;
private JTextField meaninglessTextField;
private JComboBox defaultEditorComboBox;
private JComboBox textFieldEditorComboBox;
private JComboBox panelEditorComboBox;
public ComboBoxTest()
{
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
layoutPanel = new JPanel();
layoutPanel.setLayout(new BoxLayout(layoutPanel, BoxLayout.Y_AXIS));
meaninglessTextField = new JTextField();
defaultEditorComboBox = new JComboBox(); // Just a default JComboBox.
defaultEditorComboBox.setEditable(true);
textFieldEditorComboBox = new JComboBox();
textFieldEditorComboBox.setEditable(true);
textFieldEditorComboBox.setEditor(new TextFieldEditor());
panelEditorComboBox = new JComboBox();
panelEditorComboBox.setEditable(true);
panelEditorComboBox.setEditor(new PanelEditor());
layoutPanel.add(Box.createRigidArea(new Dimension(500,0)));
layoutPanel.add(meaninglessTextField);
layoutPanel.add(defaultEditorComboBox);
layoutPanel.add(textFieldEditorComboBox);
layoutPanel.add(panelEditorComboBox);
Container contentPane = getContentPane();
contentPane.add(layoutPanel, BorderLayout.CENTER);
pack();
}
public static void main(String[] args)
{
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run()
{
new ComboBoxTest().setVisible(true);
}
});
}
private class PanelEditor extends JPanel implements ComboBoxEditor
{
public JTextField inputTextField = new JTextField();
public PanelEditor()
{
setLayout(new BorderLayout());
add(inputTextField, BorderLayout.CENTER);
}
@Override
public String getItem()
{
return inputTextField.getText();
}
@Override
public void setItem(Object newText)
{
if (newText != null) {
inputTextField.setText(newText.toString());
}
else {
inputTextField.setText("");
}
}
@Override
public Component getEditorComponent()
{
return this;
}
@Override
public void removeActionListener(ActionListener listener)
{
inputTextField.removeActionListener(listener);
}
@Override
public void addActionListener(ActionListener listener)
{
inputTextField.addActionListener(listener);
}
@Override
public void selectAll()
{
inputTextField.selectAll();
}
}
private class TextFieldEditor extends PanelEditor implements ComboBoxEditor
{
// The same, except that the editor component is now just the JTextField
// rather than the whole panel.
public TextFieldEditor()
{
}
@Override
public JTextField getEditorComponent()
{
return inputTextField;
}
}
}
注意:如果要将JLabel
添加到编辑器中,此行为将成为一个问题。然后我必须在那里放置一个JPanel
来保存标签和文本字段 试试这个:
public PanelEditor()
{
// other code...
addFocusListener(new FocusAdapter()
{
@Override
public void focusGained(FocusEvent e)
{
inputTextField.requestFocusInWindow();
}
});
}
焦点没有转移到
JPanel
;它正在传输到JComboBox
本身
您可以使用组件的setFocusable
方法阻止组件接收焦点。如果你加一行
setFocusable(false)
panelEditorComboBox.setFocusable(false)
对于上例中PanelEditor
的构造函数来说,奇怪的行为仍然存在,因为PanelEditor
实现了JPanel
,所以JPanel
的setFocusable
方法覆盖了JComboBox
的方法。由于JPanel
的setFocusable
方法基本上不起任何作用,因此不会发生任何变化
如果改为添加行
setFocusable(false)
panelEditorComboBox.setFocusable(false)
对于JFrame
本身的构造函数,则JComboBox
将无法接收焦点,但编辑器中的JTextField
将接收焦点。这不是一个完美的解决方案,因为如果编辑器本身负责关闭JComboBox
的聚焦性,那么会更好,因此您可以始终将父JComboBox
作为参数传递给编辑器的构造函数,并在那里关闭聚焦性
我不知道为什么当你有一个
JTextField
作为编辑器时,行为会有所不同。一些奇怪的摇摆运动 基本问题是组合的ui委托无法处理复合编辑器组件。在一些地方,它假设编辑器组件是它需要执行的任何配置的目标。这里具体的错误行为是,它显式地将编辑器的焦点设置为组合本身的焦点
// in BasicComboBoxUI
protected void configureEditor() {
....
editor.setFocusable(comboBox.isFocusable());
....
]
影响
- 默认情况下,面板的焦点为true,因为组合的焦点为true
- 在其构造函数中将面板的focusable强制为false没有任何效果(ui稍后以及在LAF切换时将其重置)
- 禁用组合的可聚焦也会禁用面板的
private class PanelEditor extends JPanel implements ComboBoxEditor
public boolean isFocusable() {
return false;
}
...
}
旁白:为了代码卫生,最好不要扩展视图来实现其作为ComboBoxEditor的角色(尽管这里需要一个子类的JPanel来避免问题,所以它可以说是边界:-),而是实现编辑器,让它使用经过调整的面板
也要注意,你可能会遇到复合编辑器的更多问题(检查BasiCouBi的代码,在更多的地方假设它是一个简单的无子组件),所以你可以考虑不做它,但是想一想实现你的需求的另一种方式。只是好奇:为什么需要编辑器中的标签?这是小组开始的唯一原因吗?我现在添加了SSCCE。我想要编辑器中的标签,只是因为我认为这样看起来更好,更适合组合框的外观。这是一个对话框,允许您选择溶液中四种不同离子的浓度:标签显示您指定的离子,您可以在文本字段中键入浓度。使用下拉列表可以选择不同的选项,我更希望标签直接位于下拉列表上方,而不是位于旁边。确保特定选项卡顺序的最佳方法是使用
FocusTraversalPolicy
,而不是依赖布局管理器的隐式顺序。使用它,您可以确保客户编辑器之后的下一个组件确实是所需的JTextField
,谢谢您的修复,但是您知道为什么会发生这种情况吗JPanel
s无法接收焦点。此修复程序还阻止您将选项卡移出组合框。@Docky_2009是的,我忘记了