verifyInputWhenFocusTarget 属性无效

2023-12-20

我正在尝试使用验证文本字段用户输入javax.swing.InputVerifier输入验证按预期工作,但我有一个问题VerifyInputWhenFocusTarget财产。

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

我想做的下一步是设置VerifyInputWhenFocusTarget的按钮,这样如果当前焦点所有者的验证为假,它就不会获得焦点,但我没有注意到设置的任何效果VerifyInputWhenFocusTarget财产给true即使当前焦点所有者的验证为假,也可以按下该按钮。

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

但是可以单击该按钮并且其actionPerformed()尽管如此,该方法仍会执行“受保护”的文本字段的错误验证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 = "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;
        }
    }

}

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

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);
        }
    }
}

我稍微改变了代码verify()如果没有输入任何内容,则允许更改焦点的方法(focusLost()方法检查所有文本字段是否包含某些输入,并且还通过显式调用检查输入是否有效verify()对于每个文本字段)。

当然,代码需要一些小的调整(制表符顺序、更新状态……),但这超出了本主题的范围。

结论:

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.


您拨打的电话setVerifyInputWhenFocusTarget() https://docs.oracle.com/javase/8/docs/api/javax/swing/JComponent.html#setVerifyInputWhenFocusTarget-boolean- do有影响——确切地说是确定“输入验证器是否为当前焦点所有者将在此组件请求焦点之前调用。” [强调我的] 特别是,建立以下状态:

  • Let statusText具有其初始值,或通过输入有效值恢复初始值。

  • Let tfFirstNumor tfSecondNum包含无效值时获得焦点。

然后观察

  • 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);
    

注意both必须满足上述条件才能看到单击任一按钮时的效果。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

verifyInputWhenFocusTarget 属性无效 的相关文章

随机推荐

  • Android 小部件按钮停止工作

    我有一个带有小部件的 Android 应用程序 其中有按钮 这段代码有效 小部件上的按钮停止工作当发生某些事情时 例如更改手机语言 我使用共享偏好设置 所以如果用户重新安装应用程序 无需卸载 按钮又可以工作了并且设置仍保持原来的设置 我注意
  • 如何为xamarin android实现推送通知

    我尝试按照教程进行操作 将通知推送到 Xamarin Android https learn microsoft com en us azure notification hubs xamarin notification hubs pus
  • 当我确实需要从两个类继承时如何处理CS1721?

    在我的 C 代码中 我想要一个CustomIdentity继承自的类System MarshalByRefObject and System Security Principal GenericIndentity类 然而 当我尝试编写这样的
  • 如何使用 AngularFire 对对象应用部分更新

    The save Angularfire 0 8 中的内容让我感到困惑 这是一个最小的示例 我的controllers js 文件中的一个片段 controller LandingPageController scope firebase
  • C:通过大量使用 sin() 来提高函数的性能

    我有一个 C 函数 可以根据经过的时间计算 4 个正弦值 使用 gprof 我发现这个函数使用了 100 确切地说是 100 7 哈哈 的 CPU 时间 void update sines void clock gettime CLOCK
  • OAuth2 |客户凭证资源详细信息 |已弃用

    我是 Spring Security 的新手 我遇到过使用 client credentials 作为 Grant 类型来实现 OAuth2 我正在使用下面的代码 但我得到的建议是ClientCredentialsResourceDetai
  • android 将图像上传到服务器的有效方法

    我正在寻找一种将图像从android上传到php服务器的方法 目前我正在将图像编码为base64并发送它 但是它太慢了 有没有更好的方法 我正在使用 volley 作为网络客户端 我的2分钱 根据您的目标 几乎没有什么可以改进的 如果您担心
  • OnDateSetListener() 没有被调用

    当我更改日期时 OnDateSetListener 没有被调用 甚至setMinDate day 线路不工作 我认为由于某种原因DatePickerDialog尚未注册OnDateSetListener 但无法弄清楚 我已将对话框和侦听器声
  • 将每个元素映射到表达式

    我有这个代码 import sympy import numpy as np from sympy utilities lambdify import lambdify from collections import OrderedDict
  • Android 上的 jQuery Mobile + Phonegap - 无 Ajax

    编辑 JQuery Mobile Phonegap AJAX 问题的解决方案 subdomains true config xml 中的属性是无法在phonegap 2 9 0 中工作 对子域的每个请求都将返回 200 但 ajax 不会触
  • 通过Asp.net MVC中的代码限制IP

    我的服务器受到 DDoS 攻击 因此我想限制 IP 我知道如何在 ASP NET MVC 中检测 DDoS 在 ApplicationBeginRequest 方法中 但是还有一种方法 在 ASP NET 中 对 NIC Windows 防
  • java -cp 错误:无法找到或加载主类(java.lang.ClassNotFoundException)[重复]

    这个问题在这里已经有答案了 我基本上遵循下一个教程 https picocli info running the application https picocli info running the application 我正在尝试使用以
  • 适用于 Mac 的二进制 Java 7

    是否有任何 Java 7 的二进制版本 使用 Mac BSD 端口项目 一些博客 例如在 Mac OS X 上构建 Java 7 http infernus org 2009 02 building java 7 on mac os x 有
  • System.currentTimeMillis 是否代表 UTC 时间?

    Does System currentTimeMillis 代表UTC时间还是本地系统时间 UTC 这是自 1970 年 1 月 1 日午夜以来 UTC 的毫秒数 可能是闰秒的模数 显然它依赖于本地系统clock 但它不依赖于本地系统时区
  • 浮动操作按钮下的 Admob

    我对浮动操作按钮的位置有疑问 当我从 Admob 投放广告时 fab 就结束了 我想将广告放在 fab 按钮下 但我尝试的任何方法都不起作用 当前位置风扇图像到广告 https i stack imgur com pM6s4 png 布局
  • 使用二等分来组合具有距离条件的项目

    在下面两个列表中 l1 10 33 50 67 l2 7 16 29 65 I use bisect组合两个列表中最接近的数字 我用这个代码 for s in l1 ind bisect l2 s hi len l2 1 ind abs l
  • 是什么导致 Jasper Reports 读取字体数据时抛出 java.io.IOException?

    我正在测试环境上运行一个进程 该进程需要 10 多个小时才能运行并使用 Jasper Reports v3 7 5 生成 PDF 文档 进程经常成功完成 但在某些情况下进程失败并抛出此异常 20 05 2017 02 45 23 503 E
  • 与XTR-DH Crypto++的密钥协议

    我尝试在此示例中应用 XTR DH 进行密钥协议 Alice Initialize the Diffie Hellman class with a random prime and base AutoSeededRandomPool rng
  • 如何实现索引核心风格的索引延续 monad

    我最近一直在研究 并试图理解 索 引单子 我想我已经了解了一种索引单子的风格 如下所述 无限邻域 超越单子 http blog sigfpe com 2009 02 beyond monads html 然而 我发现了一种不同风格的索引单子
  • verifyInputWhenFocusTarget 属性无效

    我正在尝试使用验证文本字段用户输入javax swing InputVerifier输入验证按预期工作 但我有一个问题VerifyInputWhenFocusTarget财产 我制作了一个标签来显示状态并被覆盖verify and shou