我有JFrame
看起来像这样:
它上面有两个JTextField
,它们之间有一个JComboBox
,底部有一个JPanel
(你看不到)。
JComboBox
的一个功能是可以为其提供自定义编辑器。这些实现了ComboBoxEditor
接口。在以下三种情况中,GUI看起来完全相同,我希望它们的行为完全相同:
JTextField
。JPanel
,其上带有JTextField
(使用BorderLayout
)。 当可编辑组合框的编辑器设置为默认值时,按 Tab 会将焦点从顶部JTextField
移动到JComboBox
上的编辑区域,然后进入另一个JTextField
。如果我创建一个自定义编辑器,其编辑器组件是JTextField
,否则会执行您期望的操作,同样的事情就会发生。
但是,如果我改为创建一个自定义编辑器,其编辑器组件为JPanel
并且JTextField
add
为其编辑,则焦点会增加一个停。如果焦点位于顶部JTextField
,则按 Tab 会将焦点移动到可编辑组合框右侧的小箭头,然后再移动到文本区域。
为什么会这样?焦点永远不会移动到框架底部的JPanel
,那么为什么持有JPanel
的{{1}}会影响组合框中的Tab键顺序?
以下是S(-ish)SCCE,其上有一个文本字段和所有三种类型的组合框:
JTextField
注意:如果我想在编辑器中添加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
放置标签和文本字段。
答案 0 :(得分:4)
基本问题是组合的ui委托无法处理复合编辑器组件。有几个地方假设编辑器组件是它需要做的任何配置的目标。这里具体的错误行为是它明确地将编辑器的可聚焦性设置为组合本身的可聚焦性
// in BasicComboBoxUI
protected void configureEditor() {
....
editor.setFocusable(comboBox.isFocusable());
....
]
影响
要修复编辑器的级别,您可以实现其isFocusable无条件地返回false:
private class PanelEditor extends JPanel implements ComboBoxEditor
public boolean isFocusable() {
return false;
}
...
}
抛开:为了代码卫生,最好不要扩展一个视图来实现其作为ComboBoxEditor的角色(即使在这里你需要一个子类化的JPanel来避免这个问题,所以它可以说是临界的:-) - 而是实现编辑器,让它使用调整的面板。
还要注意你可能会遇到更多的复合编辑器问题(检查BasicComboUI的代码以获取更多地方假设一个普通的无子组件),所以你可能会考虑不要这样做但是想到一个不同的方法达到你的要求。
答案 1 :(得分:0)
试试这个:
public PanelEditor()
{
// other code...
addFocusListener(new FocusAdapter()
{
@Override
public void focusGained(FocusEvent e)
{
inputTextField.requestFocusInWindow();
}
});
}
答案 2 :(得分:0)
重点不是转移到JPanel
;它正在转移到JComboBox
本身。
您可以使用setFocusable
方法阻止组件接收焦点。如果添加行
setFocusable(false)
到上面示例中的PanelEditor
的构造函数,然后奇怪的行为仍然存在,因为PanelEditor
implements JPanel
,所以setFocusable
方法{ {1}}会覆盖JPanel
的内容。由于JComboBox
的{{1}}方法基本上什么都不做,所以没有任何改变。
如果改为添加行
setFocusable
到JPanel
本身的构造函数,然后panelEditorComboBox.setFocusable(false)
将无法获得焦点,但编辑器中的JFrame
将会。这不是一个完美的解决方案,因为如果编辑器本身负责关闭JComboBox
的可聚焦性会更好,所以你总是可以将父JTextField
作为参数传递给编辑器的构造函数,并关闭了焦点。
当你有一个JComboBox
作为编辑器时,我不知道为什么行为会有所不同。一些奇怪的Swing的事情。