输入验证器效果不能通过单击起作用,只能通过选项卡按钮起作用
Posted
技术标签:
【中文标题】输入验证器效果不能通过单击起作用,只能通过选项卡按钮起作用【英文标题】:Input Verifier effect not work by click, just work by tab button 【发布时间】:2013-11-03 03:43:07 【问题描述】:我有一个棘手的问题!
我有一个将输入验证器设置为文本字段的表单,当用户输入不正确的值时,其他文本字段和单选按钮应该被禁用。
在第二个文本字段(姓氏)中,当用户输入不正确的值时,其他组件完全禁用,但是当用户编辑该值以更正它时,(例如通过删除数字),用户应该使用键盘tab
按钮启用其他组件(单选按钮),我也想通过单击单选按钮来启用。
这是我的代码:
public class UserDialog3 extends JDialog implements ActionListener
JButton cancelBtn, okBtn;
JTextField fNameTf, lNameTf;
JRadioButton maleRb, femaleRb;
ButtonGroup group;
JLabel fNameLbl, lNameLbl, genderLbl, tempBtn, temp3, temp2, temp1;
public UserDialog3()
add(createForm(), BorderLayout.CENTER);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocation(400, 100);
pack();
setVisible(true);
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
@Override
public void run()
new UserDialog3();
);
public JPanel createForm()
JPanel panel = new JPanel();
okBtn = new JButton("Ok");
cancelBtn = new JButton("Cancel");
tempBtn = new JLabel();
fNameLbl = new JLabel("First Name");
lNameLbl = new JLabel("Last Name");
genderLbl = new JLabel("Gender");
temp2 = new JLabel();
temp1 = new JLabel();
maleRb = new JRadioButton("Male");
femaleRb = new JRadioButton("Female");
temp3 = new JLabel();
group = new ButtonGroup();
group.add(maleRb);
group.add(femaleRb);
fNameTf = new JTextField(10);
fNameTf.setName("FnTF");
fNameTf.setInputVerifier(new MyVerifier(new JComponent[]maleRb, femaleRb, okBtn));
lNameTf = new JTextField(10);
lNameTf.setName("LnTF");
lNameTf.setInputVerifier(new MyVerifier(new JComponent[]maleRb, femaleRb, okBtn));
panel.add(fNameLbl);
panel.add(fNameTf);
panel.add(temp1);
panel.add(lNameLbl);
panel.add(lNameTf);
panel.add(temp2);
panel.add(genderLbl);
JPanel radioPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
radioPanel.add(maleRb);
radioPanel.add(femaleRb);
panel.add(radioPanel);
panel.add(temp3);
panel.add(okBtn);
panel.add(cancelBtn);
panel.add(tempBtn);
panel.setLayout(new SpringLayout());
SpringUtilities.makeCompactGrid(panel, 4, 3, 50, 10, 80, 60);
return panel;
@Override
public void actionPerformed(ActionEvent e)
public class MyVerifier extends InputVerifier
private JComponent[] component;
public MyVerifier(JComponent[] components)
component = components;
@Override
public boolean verify(JComponent input)
String name = input.getName();
if (name.equals("FnTF"))
String text = ((JTextField) input).getText().trim();
if (text.matches(".*\\d.*") || text.length() == 0)
//disable dependent components
for (JComponent r : component)
r.setEnabled(false);
return false;
else if (name.equals("LnTF"))
String text = ((JTextField) input).getText();
if (text.matches(".*\\d.*") || text.length() == 0)
//disable dependent components
for (JComponent r : component)
r.setEnabled(false);
return false;
//enable dependent components
for (JComponent r : component)
r.setEnabled(true);
return true;
【问题讨论】:
那么问题是什么? @jzd 问题是如何通过单击启用单选按钮? 当您的名字输入字段错误时,它不应该让您转到姓氏字段。不是吗? 那为什么你说姓氏字段是正确的但单选按钮被禁用了? @Sage 当用户第一次输入错误的值时(在第二个文本字段上),然后单选按钮正确禁用,当用户将错误的值编辑为正确的值时,他/她必须按tab
按钮以启用单选按钮以选择其中之一。我想更改用户可以通过单击启用单选按钮。
【参考方案1】:
InputVerifier
类的目的是帮助客户通过带有文本字段的 GUI 支持平滑的焦点导航。在焦点转移到另一个请求它的 Swing 组件之前,输入验证器的shouldYieldFocus
方法被调用(它要求verify
函数验证数据)。仅当该方法返回 true
时才会转移焦点。
请尝试解决your previous post 中提到的有关使用InutVerifier
、verify
和shouldYieldFunction
的问题。如果你不改变你的做法,你将来会有危险。从验证功能中删除启用和禁用代码的组件。
您在这篇文章中遇到的问题:在这种情况下,真正发生的情况是,当您的数据无效并且您尝试通过单击另一个组件来失去输入文本字段焦点时,您的 JRadioButtons
被禁用。在重新启用之前,禁用的无法聚焦。由于输入验证器响应焦点丢失事件,单击disabled RadioButton
不会导致焦点导航,因此不会调用ShouldYieldFocus(which calls verify)
来重新启用您的组件。
按下选项卡有效,因为它根据 Swing 的焦点遍历策略将焦点发送到您的第二个文本输入字段。因此,在第一个输入文本字段上发生焦点丢失事件,这一次 InputVerifier
的验证函数被调用,最终启用您的组件。要更好地理解问题,请尝试使用一个JRadioButton
和一个JTextFeild
重写您自己的示例。
尝试在您的文本字段中使用DocumentListener
。在发生数据插入和删除事件时,使用InputVerifier
检查您的数据有效性,然后启用/禁用相关组件。
我正在编写一个示例代码 sn-ps 来演示如何将 DocumentListener
添加到您的 fNameTF
和 lNameTF
文本字段将解决您的问题:
fNameTF.getDocument().addDocumentListener(new DocumentListener()
@Override
public void insertUpdate(DocumentEvent e)
doOnDataValidity(verifier.verify(fNameTF));
@Override
public void removeUpdate(DocumentEvent e)
doOnDataValidity(verifier.verify(fNameTF));
@Override
public void changedUpdate(DocumentEvent e)
);
doOnValidity(boolean isValid)
函数如下:
public void doOnDataValidity(boolean isDataValid)
if(isDataValid)
//enable your components
else
//disable your components
以同样的方式将 DocumentListener 添加到您的lNameTf.getDocument()
。
教程资源: How to use DocumentListener。
【讨论】:
JavaDocs 声明verify
方法“应该没有副作用”。 OP 正在更改 verify
方法中其他组件的状态,这是实际问题。相反,应该鼓励 OP 使用不同的方法来确定是否应该更改组件状态,例如 PropertyChangeListener
- 恕我直言 - 另一个问题是,虽然我喜欢 DocumentFilter
s 并且不会反对使用在这种情况下,它并不能解决问题
我也会考虑将单个 InputVerifier
用于每个字段的逻辑相同的多个组件...
@MadProgrammer,关于verify
和shouldYeildFocus
函数,我已经在his another question 中详细解释过。还有关于他如何使用单输入验证器。这就是我跳过这篇文章的原因。
然而,在这篇文章中,虽然我已经指出这不是最好的解决方案:mixing verifier with document listener
。但是我自己一直在问验证者的验证功能是否公开,为什么使用它来验证然后使用该条件来启用或禁用DocumentListener
的插入和删除操作上下文中的组件会出现问题?至少 它支持在数据有效之前不让输入字段失去焦点!
我认为InputVerifier
负责确定它过去的组件的有效性,仅此而已。控制器有责任通过它们各自的模型/侦听器根据对任何给定字段的更改来确定组件的状态...恕我直言;)以上是关于输入验证器效果不能通过单击起作用,只能通过选项卡按钮起作用的主要内容,如果未能解决你的问题,请参考以下文章
使用 Passport 通过 Facebook 进行身份验证不起作用
列表框数据模板 - 项目只能通过单击子元素来选择,而不仅仅是项目上的任何位置