VerifyInputWhenFocusTarget属性不起作用 [英] VerifyInputWhenFocusTarget property has no effect

查看:641
本文介绍了VerifyInputWhenFocusTarget属性不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用 javax.swing.InputVerifier 验证文本字段用户输入,输入验证按预期工作,但是我有一个关于 VerifyInputWhenFocusTarget 属性。



我做了一个标签来显示状态并覆盖 verify() shouldYieldFocus()方法 InputVerifier 子类,并且工作正常。 b

下一步我想要做的是设置按钮的 VerifyInputWhenFocusTarget ,这样它就不会获得焦点,当前焦点所有者是错误的,但我没有注意到将 VerifyInputWhenFocusTarget 属性设置为 true 的任何效果,按钮可能即使在当前焦点所有者的验证是错误的情况下也会被按下。

也许我不明白文档 - 我认为设置 VerifyInputWhenFocusTarget code>按钮属性 true code>将防止按钮在文本字段的错误验证情况下被点击时获得焦点。此外,我(错)了解如果按钮无法获得焦点,那么它的 actionPerformed()方法将不会被调用。



然而,按钮可以被点击,并且它的 actionPerformed()方法被执行,然而被文本字段's守护' code> javax.swing.InputVerifier



这里是剥离的代码:



package verifiertest;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

import javax.swing.UIManager;
import java.awt.GridLayout;
import java.math.BigDecimal;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.JTextField;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComponent;

import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class TestVerifier {

private JFrame frmInputverifierTest;
private JTextField tfFirstNum;
private JTextField tfSecondNum;
private JLabel lblStatus;
private String statusText =输入数字并按下\Start!\按钮...;

public static void main(String [] args){
EventQueue.invokeLater(new Runnable(){
public void run(){
try {
TestVerifier window = new TestVerifier();
window.frmInputverifierTest.setVisible(true);
} catch(Exception e){
e.printStackTrace();
}
}
});

$ b $ public TestVerifier(){
initialize();


private void initialize(){
frmInputverifierTest = new JFrame();
frmInputverifierTest.setTitle(InputVerifier Test);
frmInputverifierTest.setBounds(100,100,500,450);
frmInputverifierTest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panelContainer = new JPanel();
panelContainer.setBorder(new EmptyBorder(5,5,5));
frmInputverifierTest.getContentPane()。add(panelContainer,BorderLayout.CENTER);
panelContainer.setLayout(new BorderLayout(0,0));

JPanel panelInput = new JPanel();
panelInput.setBorder(new TitledBorder(null,Input,TitledBorder.LEADING,TitledBorder.TOP,null,null));
panelContainer.add(panelInput,BorderLayout.NORTH);
panelInput.setLayout(new GridLayout(2,2,10,4));

JLabel lblFirstNum = new JLabel(Number#1:);
lblFirstNum.setHorizo​​ntalAlignment(SwingConstants.TRAILING);
panelInput.add(lblFirstNum);

tfFirstNum = new JTextField();
panelInput.add(tfFirstNum);
tfFirstNum.setColumns(10);
//设置验证者
MyTxtVerifier txtVerifier = new MyTxtVerifier();
tfFirstNum.setInputVerifier(txtVerifier);

JLabel lblSecondNum = new JLabel(Number#2:);
lblSecondNum.setHorizo​​ntalAlignment(SwingConstants.TRAILING);
panelInput.add(lblSecondNum);

tfSecondNum = new JTextField();
panelInput.add(tfSecondNum);
tfSecondNum.setColumns(10);
//设置验证器
tfSecondNum.setInputVerifier(txtVerifier);

JPanel panelOutput = new JPanel();
panelOutput.setBorder(new TitledBorder(UIManager.getBorder(TitledBorder.border),Output(not used at now),TitledBorder.LEADING,TitledBorder.TOP,null,null));
panelContainer.add(panelOutput,BorderLayout.CENTER);

JPanel panelSouth = new JPanel();
panelSouth.setBorder(null);
panelContainer.add(panelSouth,BorderLayout.SOUTH);
panelSouth.setLayout(new GridLayout(0,1,0,0));

JPanel panelStatus = new JPanel();
FlowLayout flowLayout_1 =(FlowLayout)panelStatus.getLayout();
flowLayout_1.setAlignment(FlowLayout.LEFT);
panelStatus.setBorder(new TitledBorder(null,Status,TitledBorder.LEADING,TitledBorder.TOP,null,null));
panelSouth.add(panelStatus);

lblStatus = new JLabel(statusText);
panelStatus.add(lblStatus);

JPanel panelActions = new JPanel();
panelActions.setBorder(new TitledBorder(null,Actions,TitledBorder.LEADING,TitledBorder.TOP,null,null));
FlowLayout flowLayout =(FlowLayout)panelActions.getLayout();
flowLayout.setAlignment(FlowLayout.RIGHT);
panelSouth.add(panelActions);

JButton btnHelp = new JButton(?);
btnHelp.setVerifyInputWhenFocusTarget(false); //< - 没有效果!
btnHelp.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(frmInputverifierTest,Help button pressed ...,Help,JOptionPane。 PLAIN_MESSAGE);
}
});
panelActions.add(btnHelp);

JButton btnStart = new JButton(Start!);
btnStart.setVerifyInputWhenFocusTarget(true); //< - 没有效果!
btnStart.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(frmInputverifierTest,Start button pressed ...,Start,JOptionPane。 PLAIN_MESSAGE);
}
});
panelActions.add(btnStart);
btnHelp.setPreferredSize(btnStart.getPreferredSize()); //使按钮大小相等
}

//一个内部类,所以它可以访问父字段
public class MyTxtVerifier extends InputVerifier {
//这个方法应该没有副作用
@Override
public boolean verify(JComponent input){
String text =((JTextField)input).getText();
尝试{
BigDecimal value = new BigDecimal(text);
if(value.floatValue()<= 0.0)
返回false;
return(value.scale()<= Math.abs(4)); //为什么不是4而不是Math.abs(4)?
} catch(Exception e){
return false;



//这个方法可以有副作用
@Override
public boolean shouldYieldFocus(JComponent input){
String statusOld , 状态;

statusOld = statusText; //记住原始文本
boolean isOK = verify(input); //调用重写的方法
if(isOK)
status = statusOld;
else
status =错误:参数应该是正数,最多4个小数位;
lblStatus.setText(status);
// return super.shouldYieldFocus(input);
return isOK;



$ b code
$ b

在这里是测试应用程序的屏幕截图:



可以看出,有两个按钮。其中一个将 VerifyInputWhenFocusTarget 属性设置为 true ,另一个属性设置为 false ,但在虚假的文本字段验证的情况下点击按钮时没有任何区别。通过输入负数或具有4位十进制数字的某个数字可能会引起错误的验证。 InputVerifier 确实可以防止将焦点转移到另一个文本字段,但是并不妨碍激活按钮。由于它没有任何意义(至少对我来说没有意义),按钮可以在没有获得焦点的情况下被激活,当文本字段验证方法不应该激活 Start!按钮时 verify()返回 false




编辑:

现在我已经改变了代码,以适应垃圾的建议 FocusListener ),这里是工作示例:

 lang-java prettyprint-override>  package verifiertest; 

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.text.JTextComponent;
import javax.swing.UIManager;
import java.awt.GridLayout;
import java.math.BigDecimal;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.JTextField;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComponent;

import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ActionEvent;

public class TestVerifier实现了FocusListener {

private JFrame frmInputverifierTest;
private JTextField tfFirstNum;
private JTextField tfSecondNum;
private JLabel lblStatus;
私人JButton btnStart;
private String statusText =输入数字并按下\Start!\按钮...;

public static void main(String [] args){
EventQueue.invokeLater(new Runnable(){
public void run(){
try {
TestVerifier window = new TestVerifier();
window.frmInputverifierTest.setVisible(true);
} catch(Exception e){
e.printStackTrace();
}
}
});

$ b $ public TestVerifier(){
initialize();


private void initialize(){
frmInputverifierTest = new JFrame();
frmInputverifierTest.setTitle(InputVerifier Test);
frmInputverifierTest.setBounds(100,100,500,450);
frmInputverifierTest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panelContainer = new JPanel();
panelContainer.setBorder(new EmptyBorder(5,5,5));
frmInputverifierTest.getContentPane()。add(panelContainer,BorderLayout.CENTER);
panelContainer.setLayout(new BorderLayout(0,0));

JPanel panelInput = new JPanel();
panelInput.setBorder(new TitledBorder(null,Input,TitledBorder.LEADING,TitledBorder.TOP,null,null));
panelContainer.add(panelInput,BorderLayout.NORTH);
panelInput.setLayout(new GridLayout(2,2,10,4));

JLabel lblFirstNum = new JLabel(Number#1:);
lblFirstNum.setHorizo​​ntalAlignment(SwingConstants.TRAILING);
panelInput.add(lblFirstNum);

tfFirstNum = new JTextField();
panelInput.add(tfFirstNum);
tfFirstNum.setColumns(10);
//设置验证者
MyTxtVerifier txtVerifier = new MyTxtVerifier();
tfFirstNum.setInputVerifier(txtVerifier);
//添加焦点侦听器
tfFirstNum.addFocusListener(this);

JLabel lblSecondNum = new JLabel(Number#2:);
lblSecondNum.setHorizo​​ntalAlignment(SwingConstants.TRAILING);
panelInput.add(lblSecondNum);

tfSecondNum = new JTextField();
panelInput.add(tfSecondNum);
tfSecondNum.setColumns(10);
//设置验证器
tfSecondNum.setInputVerifier(txtVerifier);
//添加焦点侦听器
tfSecondNum.addFocusListener(this);

JPanel panelOutput = new JPanel();
panelOutput.setBorder(new TitledBorder(UIManager.getBorder(TitledBorder.border),Output(not used at now),TitledBorder.LEADING,TitledBorder.TOP,null,null));
panelContainer.add(panelOutput,BorderLayout.CENTER);

JPanel panelSouth = new JPanel();
panelSouth.setBorder(null);
panelContainer.add(panelSouth,BorderLayout.SOUTH);
panelSouth.setLayout(new GridLayout(0,1,0,0));

JPanel panelStatus = new JPanel();
FlowLayout flowLayout_1 =(FlowLayout)panelStatus.getLayout();
flowLayout_1.setAlignment(FlowLayout.LEFT);
panelStatus.setBorder(new TitledBorder(null,Status,TitledBorder.LEADING,TitledBorder.TOP,null,null));
panelSouth.add(panelStatus);

lblStatus = new JLabel(statusText);
panelStatus.add(lblStatus);

JPanel panelActions = new JPanel();
panelActions.setBorder(new TitledBorder(null,Actions,TitledBorder.LEADING,TitledBorder.TOP,null,null));
FlowLayout flowLayout =(FlowLayout)panelActions.getLayout();
flowLayout.setAlignment(FlowLayout.RIGHT);
panelSouth.add(panelActions);

JButton btnHelp = new JButton(?);
btnHelp.setVerifyInputWhenFocusTarget(false); //< - 没有效果!
btnHelp.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(frmInputverifierTest,Help button pressed ...,Help,JOptionPane。 PLAIN_MESSAGE);
}
});
panelActions.add(btnHelp);

btnStart = new JButton(Start!);
btnStart.setEnabled(false);
btnStart.setVerifyInputWhenFocusTarget(true); //< - 没有效果!
btnStart.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(frmInputverifierTest,Start button pressed ...,Start,JOptionPane。 PLAIN_MESSAGE);
}
});
panelActions.add(btnStart);
btnHelp.setPreferredSize(btnStart.getPreferredSize()); //使按钮的大小相等
}

//一个内部类,所以它可以访问父字段
public class MyTxtVerifier extends InputVerifier {
//这个方法应该没有副作用
@Override
public boolean verify(JComponent input){
String text =((JTextField)input).getText();
//在没有输入时允许改变焦点
if(text.isEmpty())
return true;
尝试{
BigDecimal value = new BigDecimal(text);
if(value.floatValue()<= 0.0)
返回false;
return(value.scale()<= Math.abs(4)); //为什么不是4而不是Math.abs(4)?
} catch(Exception e){
return false;



//这个方法可以有副作用
@Override
public boolean shouldYieldFocus(JComponent input){
String statusOld , 状态;

statusOld = statusText; //记住原始文本
boolean isOK = verify(input); //调用重写的方法
if(isOK)
status = statusOld;
else {
btnStart.setEnabled(false);
status =错误:参数应该是正数,最多4个小数位;
}
lblStatus.setText(status);
// return super.shouldYieldFocus(input);
return isOK;



@Override
public void focusGained(FocusEvent e){
//在焦点上无所事事
}

@Override
public void focusLost(FocusEvent e){
//如果我们要在focusLost()中显示一个消息框,不要被触发两次
if(e.isTemporary())
return;
final JTextComponent c =(JTextComponent)e.getSource();
//如果有更多的文本字段,但
//我们只验证其中的一些
if(c.equals(tfFirstNum)|| c.equals(tfSecondNum)){
//是否都是文本字段有效?
if(c.getInputVerifier()。verify(tfFirstNum)& c.getInputVerifier()。verify(tfSecondNum)&&
!tfFirstNum.getText()。isEmpty()& &!tfSecondNum.getText()。isEmpty())
btnStart.setEnabled(true);
else
btnStart.setEnabled(false);


$ b $ / code $ / pre
$ b

我稍微改变了代码如果没有输入任何内容( focusLost()),方法检查是否所有文本字段包含一些输入,并通过为每个文本字段明确调用 verify())来检查输入是否有效。


$ b $当然,代码需要一些小的调整(tab顺序,更新状态...),但这不在本主题的范围之内。



<虽然 VerifyInputWhenFocusTarget 属性显然是有用的(在这个例子中是这样的): 即使在文本字段验证是 false )的情况下,按钮可以获得焦点,但我仍然认为文档不是在描述所有相当违反直觉的重要副作用方面非常精确,所以需要进一步的检验和调查离线(也许分析源代码),除了阅读文档。

/docs.oracle.com/javase/8/docs/api/javax/swing/JComponent.html#setVerifyInputWhenFocusTarget-boolean-rel =nofollow> setVerifyInputWhenFocusTarget() do 有效果 - 确切地说,在该组件请求焦点之前,将调用当前焦点所有者的输入验证程序是否会被调用。设置 statusText

c>有它的初始值,或者通过输入一个有效的值来恢复初始值。 >或 tfSecondNum 在包含无效值的情况下具有焦点。 >然后观察


  • 点击离开 statusText

     不变,这意味着焦点组件的输入验证符被调用,而不是 > btnHelp.setVerifyInputWhenFocusTarget(假); 


  • 点击开始设置 statusText

    $ b>
    来反映一个错误, btnStart.setVerifyInputWhenFocusTarget(真);




请注意 必须满足上述条件才能看到任何一个按钮被点击的效果。


I am attempting to validate the text field user inputs using javax.swing.InputVerifier and the input validation works as expected but I have a problem regarding VerifyInputWhenFocusTarget property.

I've made a label to show the status and overridden verify() and shouldYieldFocus() methods of InputVerifier subclass and that works fine.

The next step I wanted to do was to set the VerifyInputWhenFocusTarget of the button so it wouldn't get the focus in case the validation of the current focus owner was false, but I did not notice any effect of setting the VerifyInputWhenFocusTarget property to true and the button could be pressed even when the validation of the current focus owner was false.

Maybe I do not understand the docs - I thought setting the VerifyInputWhenFocusTarget property of the button to true would prevent the button to get the focus when clicked under the circumstances of the false validation of the text field. Furthermore, I (mis)understood if the button couldn't get the focus then its actionPerformed() method wouldn't be called.

However the button can be clicked and its actionPerformed() method gets executed nevertheless of the false validation of the text field(s) 'guarded' by javax.swing.InputVerifier.

Here is the stripped code:

package verifiertest;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

import javax.swing.UIManager;
import java.awt.GridLayout;
import java.math.BigDecimal;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.JTextField;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComponent;

import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class TestVerifier {

    private JFrame frmInputverifierTest;
    private JTextField tfFirstNum;
    private JTextField tfSecondNum;
    private JLabel lblStatus;
    private String statusText = "Input the numbers and press the \"Start!\" button...";

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TestVerifier window = new TestVerifier();
                    window.frmInputverifierTest.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public TestVerifier() {
        initialize();
    }

    private void initialize() {
        frmInputverifierTest = new JFrame();
        frmInputverifierTest.setTitle("InputVerifier Test");
        frmInputverifierTest.setBounds(100, 100, 500, 450);
        frmInputverifierTest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panelContainer = new JPanel();
        panelContainer.setBorder(new EmptyBorder(5, 5, 5, 5));
        frmInputverifierTest.getContentPane().add(panelContainer, BorderLayout.CENTER);
        panelContainer.setLayout(new BorderLayout(0, 0));

        JPanel panelInput = new JPanel();
        panelInput.setBorder(new TitledBorder(null, "Input", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panelContainer.add(panelInput, BorderLayout.NORTH);
        panelInput.setLayout(new GridLayout(2, 2, 10, 4));

        JLabel lblFirstNum = new JLabel("Number #1:");
        lblFirstNum.setHorizontalAlignment(SwingConstants.TRAILING);
        panelInput.add(lblFirstNum);

        tfFirstNum = new JTextField();
        panelInput.add(tfFirstNum);
        tfFirstNum.setColumns(10);
        // setup the verifier
        MyTxtVerifier txtVerifier = new MyTxtVerifier();
        tfFirstNum.setInputVerifier(txtVerifier);

        JLabel lblSecondNum = new JLabel("Number #2:");
        lblSecondNum.setHorizontalAlignment(SwingConstants.TRAILING);
        panelInput.add(lblSecondNum);

        tfSecondNum = new JTextField();
        panelInput.add(tfSecondNum);
        tfSecondNum.setColumns(10);
        // setup the verifier
        tfSecondNum.setInputVerifier(txtVerifier);

        JPanel panelOutput = new JPanel();
        panelOutput.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Output (not used at the moment)", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panelContainer.add(panelOutput, BorderLayout.CENTER);

        JPanel panelSouth = new JPanel();
        panelSouth.setBorder(null);
        panelContainer.add(panelSouth, BorderLayout.SOUTH);
        panelSouth.setLayout(new GridLayout(0, 1, 0, 0));

        JPanel panelStatus = new JPanel();
        FlowLayout flowLayout_1 = (FlowLayout) panelStatus.getLayout();
        flowLayout_1.setAlignment(FlowLayout.LEFT);
        panelStatus.setBorder(new TitledBorder(null, "Status", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panelSouth.add(panelStatus);

        lblStatus = new JLabel(statusText);
        panelStatus.add(lblStatus);

        JPanel panelActions = new JPanel();
        panelActions.setBorder(new TitledBorder(null, "Actions", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        FlowLayout flowLayout = (FlowLayout) panelActions.getLayout();
        flowLayout.setAlignment(FlowLayout.RIGHT);
        panelSouth.add(panelActions);

        JButton btnHelp = new JButton("?");
        btnHelp.setVerifyInputWhenFocusTarget(false);   // <-- NO EFFECT!?
        btnHelp.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frmInputverifierTest, "Help button pressed...", "Help", JOptionPane.PLAIN_MESSAGE);
            }
        });
        panelActions.add(btnHelp);

        JButton btnStart = new JButton("Start!");
        btnStart.setVerifyInputWhenFocusTarget(true);   // <-- NO EFFECT!?
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frmInputverifierTest, "Start button pressed...", "Start", JOptionPane.PLAIN_MESSAGE);
            }
        });
        panelActions.add(btnStart);
        btnHelp.setPreferredSize(btnStart.getPreferredSize());  // make buttons equal in size
    }

    // an inner class so it can access parent fields
    public class MyTxtVerifier extends InputVerifier {
        // This method should have no side effects
        @Override
        public boolean verify(JComponent input) {
            String text = ((JTextField)input).getText();
            try {
                BigDecimal value = new BigDecimal(text);
                if(value.floatValue() <= 0.0)
                    return false;
                return (value.scale() <= Math.abs(4));  // why not 4 instead of Math.abs(4)??
            } catch (Exception e) {
                return false;
            }
        }

        // This method can have side effects
        @Override
        public boolean shouldYieldFocus(JComponent input) {
            String statusOld, status;

            statusOld = statusText;         // remember the original text
            boolean isOK = verify(input);   // call overridden method
            if(isOK)
                status = statusOld;
            else
                status = "Error: The parameter should be a positive number up to 4 decimal places";
            lblStatus.setText(status);
            // return super.shouldYieldFocus(input);
            return isOK;
        }
    }

}

And here is the screenshot of the test application:

As can be seen, there are two buttons. One of them has the VerifyInputWhenFocusTarget property set to true and the other one has the same property set to false but there isn't any difference when the button is clicked under the circumstance of false text field validation. The false validation can be provoked by entering negative number or some number with more than 4 decimal digits. The InputVerifier indeed prevents transfering the focus to the other text field but it does not prevent activating the button. Since it does not make sense (at least not to me) the button could be activated without first getting the focus, there shouldn't be a possibility to activate the Start! button when the text field validation method verify() returned false.


EDIT:

I have now changed the code to accommodate the trashgod's suggestion (conditioning the enabled state of the Start! button with FocusListener) and here is the working example:

package verifiertest;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.text.JTextComponent;
import javax.swing.UIManager;
import java.awt.GridLayout;
import java.math.BigDecimal;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.JTextField;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComponent;

import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ActionEvent;

public class TestVerifier implements FocusListener {

    private JFrame frmInputverifierTest;
    private JTextField tfFirstNum;
    private JTextField tfSecondNum;
    private JLabel lblStatus;
    private JButton btnStart;
    private String statusText = "Input the numbers and press the \"Start!\" button...";

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TestVerifier window = new TestVerifier();
                    window.frmInputverifierTest.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public TestVerifier() {
        initialize();
    }

    private void initialize() {
        frmInputverifierTest = new JFrame();
        frmInputverifierTest.setTitle("InputVerifier Test");
        frmInputverifierTest.setBounds(100, 100, 500, 450);
        frmInputverifierTest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panelContainer = new JPanel();
        panelContainer.setBorder(new EmptyBorder(5, 5, 5, 5));
        frmInputverifierTest.getContentPane().add(panelContainer, BorderLayout.CENTER);
        panelContainer.setLayout(new BorderLayout(0, 0));

        JPanel panelInput = new JPanel();
        panelInput.setBorder(new TitledBorder(null, "Input", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panelContainer.add(panelInput, BorderLayout.NORTH);
        panelInput.setLayout(new GridLayout(2, 2, 10, 4));

        JLabel lblFirstNum = new JLabel("Number #1:");
        lblFirstNum.setHorizontalAlignment(SwingConstants.TRAILING);
        panelInput.add(lblFirstNum);

        tfFirstNum = new JTextField();
        panelInput.add(tfFirstNum);
        tfFirstNum.setColumns(10);
        // setup the verifier
        MyTxtVerifier txtVerifier = new MyTxtVerifier();
        tfFirstNum.setInputVerifier(txtVerifier);
        // add focus listener
        tfFirstNum.addFocusListener(this);

        JLabel lblSecondNum = new JLabel("Number #2:");
        lblSecondNum.setHorizontalAlignment(SwingConstants.TRAILING);
        panelInput.add(lblSecondNum);

        tfSecondNum = new JTextField();
        panelInput.add(tfSecondNum);
        tfSecondNum.setColumns(10);
        // setup the verifier
        tfSecondNum.setInputVerifier(txtVerifier);
        // add focus listener
        tfSecondNum.addFocusListener(this);

        JPanel panelOutput = new JPanel();
        panelOutput.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Output (not used at the moment)", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panelContainer.add(panelOutput, BorderLayout.CENTER);

        JPanel panelSouth = new JPanel();
        panelSouth.setBorder(null);
        panelContainer.add(panelSouth, BorderLayout.SOUTH);
        panelSouth.setLayout(new GridLayout(0, 1, 0, 0));

        JPanel panelStatus = new JPanel();
        FlowLayout flowLayout_1 = (FlowLayout) panelStatus.getLayout();
        flowLayout_1.setAlignment(FlowLayout.LEFT);
        panelStatus.setBorder(new TitledBorder(null, "Status", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panelSouth.add(panelStatus);

        lblStatus = new JLabel(statusText);
        panelStatus.add(lblStatus);

        JPanel panelActions = new JPanel();
        panelActions.setBorder(new TitledBorder(null, "Actions", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        FlowLayout flowLayout = (FlowLayout) panelActions.getLayout();
        flowLayout.setAlignment(FlowLayout.RIGHT);
        panelSouth.add(panelActions);

        JButton btnHelp = new JButton("?");
        btnHelp.setVerifyInputWhenFocusTarget(false);   // <-- NO EFFECT!?
        btnHelp.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frmInputverifierTest, "Help button pressed...", "Help", JOptionPane.PLAIN_MESSAGE);
            }
        });
        panelActions.add(btnHelp);

        btnStart = new JButton("Start!");
        btnStart.setEnabled(false);
        btnStart.setVerifyInputWhenFocusTarget(true);   // <-- NO EFFECT!?
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frmInputverifierTest, "Start button pressed...", "Start", JOptionPane.PLAIN_MESSAGE);
            }
        });
        panelActions.add(btnStart);
        btnHelp.setPreferredSize(btnStart.getPreferredSize());  // make buttons equal in size
    }

    // an inner class so it can access parent fields
    public class MyTxtVerifier extends InputVerifier {
        // This method should have no side effects
        @Override
        public boolean verify(JComponent input) {
            String text = ((JTextField)input).getText();
            // to allow changing focus when nothing is entered
            if(text.isEmpty())
                return true;
            try {
                BigDecimal value = new BigDecimal(text);
                if(value.floatValue() <= 0.0)
                    return false;
                return (value.scale() <= Math.abs(4));  // why not 4 instead of Math.abs(4)??
            } catch (Exception e) {
                return false;
            }
        }

        // This method can have side effects
        @Override
        public boolean shouldYieldFocus(JComponent input) {
            String statusOld, status;

            statusOld = statusText;         // remember the original text
            boolean isOK = verify(input);   // call overridden method
            if(isOK)
                status = statusOld;
            else {
                btnStart.setEnabled(false);
                status = "Error: The parameter should be a positive number up to 4 decimal places";
            }
            lblStatus.setText(status);
            // return super.shouldYieldFocus(input);
            return isOK;
        }
    }

    @Override
    public void focusGained(FocusEvent e) {
        // nothing to do on focus gained
    }

    @Override
    public void focusLost(FocusEvent e) {
        // in case we want to show a message box inside focusLost() - not to be fired twice
        if(e.isTemporary())
            return;
        final JTextComponent c = (JTextComponent)e.getSource();
        // in case there are more text fields but
        // we are validating only some of them
        if(c.equals(tfFirstNum) || c.equals(tfSecondNum)) {
            // are all text fields valid?
            if(c.getInputVerifier().verify(tfFirstNum) && c.getInputVerifier().verify(tfSecondNum) &&
                    !tfFirstNum.getText().isEmpty() && !tfSecondNum.getText().isEmpty())
                btnStart.setEnabled(true);
            else
                btnStart.setEnabled(false);
        }
    }
}

I have slightly changed the code of verify() method to allow changing the focus if nothing is entered (focusLost() method checks if all text fields contain some input and it also checks if the inputs are valid by explicitly calling verify() for each of the text fields).

The code, of course, needs some minor tweaking (tab order, updating the status, ...) but that is out of the scope of this topic.

Conclusion:

Although VerifyInputWhenFocusTarget property is apparently useful (here in the example the ? button can gain focus even in case of text field(s) validation was false), I am still holding my opinion the documentation is not quite precise in describing all the important side effects which are rather counterintuitive so there is a need of doing further testing and investigations (perhaps analyzing the source code) besides just reading the docs.

解决方案

Your calls to setVerifyInputWhenFocusTarget() do have a effect—precisely the effect of determining "whether [the] input verifier for the current focus owner will be called before this component requests focus." [emphasis mine] In particular, establish the following state:

  • Let statusText have its initial value, or restore the initial value by entering a valid value.

  • Let tfFirstNumor tfSecondNum have focus while containing an invalid value.

Then observe that

  • Clicking on ? leaves statusText unchanged, meaning that the focused component's input verifier was not called, as prescribed by

    btnHelp.setVerifyInputWhenFocusTarget(false);
    

  • Clicking on Start sets statusText to reflect an error, meaning that the focused component's input verifier was called, as prescribed by

    btnStart.setVerifyInputWhenFocusTarget(true);
    

Note that both conditions above must be met to see the effect when either button is clicked.

这篇关于VerifyInputWhenFocusTarget属性不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆