【发布时间】:2013-08-28 14:38:06
【问题描述】:
我有一个看起来像这样的JFrame:
上面有两个JTextFields,一个JComboBox在它们之间,一个JPanel在底部(你看不到)。
JComboBox 的一个特点是它可以被赋予一个自定义编辑器。这些实现了ComboBoxEditor 接口。在以下三种情况下,GUI 看起来完全一样,我希望它们的行为完全相同:
- 我没有指定自定义编辑器,而是使用默认编辑器。
- 我创建了一个自定义编辑器,其编辑器组件为
JTextField。 - 我创建了一个自定义编辑器,其编辑器组件是
JPanel,上面带有JTextField(使用BorderLayout)。
当可编辑组合框的编辑器设置为默认值时,按 Tab 将焦点从顶部 JTextField 移到 JComboBox 上的编辑区域,然后移到另一个 @ 987654335@。如果我创建一个自定义编辑器,其编辑器组件是JTextField,否则会按照您的预期进行,同样的事情也会发生。
但是,如果我改为创建一个自定义编辑器,其编辑器组件是 JPanel 并带有 JTextField added 到它,焦点会额外停止。如果焦点位于顶部JTextField,则按下 Tab 会将焦点移至可编辑组合框右侧的小箭头,然后再移入文本区域。
为什么会这样?焦点永远不会移动到框架底部的JPanel,那么为什么存在JPanel 持有JTextField 会影响组合框上的Tab 顺序?
以下是一个 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 来保存标签和文本字段。
【问题讨论】:
-
是的,请显示SSCCE。只是好奇:为什么你需要编辑器中的标签?小组开始的唯一原因是什么?
-
我现在添加了 SSCCE。我想要编辑器中的标签只是因为我认为这样看起来更好,并且更适合组合框的外观。这是一个对话框,允许您选择溶液中四种不同离子的浓度:标签显示您指定的离子,您可以在文本字段中输入浓度。使用下拉列表可以选择不同的离子,我宁愿将标签直接放在下拉列表上方,而不是放在一边。
-
确保特定选项卡顺序的最佳方法是使用
FocusTraversalPolicy,而不是依赖于布局管理器的隐式顺序。使用它,您可以确保客户编辑器之后的下一个组件确实是所需的JTextField
标签: java swing focus jcombobox