3

を使用してテキスト フィールドのユーザー入力を検証しようとしていますがjavax.swing.InputVerifier、入力の検証は期待どおりに機能しますが、プロパティに関して問題がVerifyInputWhenFocusTargetあります。

サブクラスのステータスとオーバーライドverify()およびshouldYieldFocus()メソッドを表示するラベルを作成しましたが、それは正常に機能します。InputVerifier

私がやりたかった次のステップは、ボタンの を設定して、現在のフォーカス所有者の検証が false の場合にフォーカスを取得しないようにすることでしたが、プロパティをVerifyInputWhenFocusTargetに設定した効果に気付かず、ボタンが現在のフォーカス所有者の検証が false の場合でも押されます。VerifyInputWhenFocusTargettrue

ドキュメントを理解していない可能性があります-ボタンの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;
        }
    }

}

テスト アプリケーションのスクリーンショットは次のとおりです。

InputVerifier テストのスクリーンショット

ご覧のとおり、ボタンが 2 つあります。それらの 1 つはVerifyInputWhenFocusTargetプロパティが に設定されtrue、もう 1 つは同じプロパティが に設定されてfalseいますが、テキスト フィールドの検証が誤っている状況でボタンをクリックしても違いはありません。誤った検証は、負の数または 4 桁を超える数を入力することによって引き起こされる可能性があります。InputVerifier確かに、フォーカスを他のテキスト フィールドに移動することはできませんが、ボタンをアクティブにすることはできません。最初にフォーカスを取得せずにボタンをアクティブにすることは (少なくとも私には) 意味がないためStart!、テキスト フィールドの検証メソッドverify()が返されたときにボタンをアクティブにする可能性はありませんfalse


編集:

Trashgod の提案に対応するようにコードを変更しました (Start!ボタンの有効状態を で条件付けますFocusListener)。実際の例は次のとおりです。

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()、各テキスト フィールドを明示的に呼び出して入力が有効かどうかもチェックします)。

もちろん、コードには若干の微調整 (タブ オーダー、ステータスの更新など) が必要ですが、それはこのトピックの範囲外です。

結論:

VerifyInputWhenFocusTargetプロパティは明らかに便利ですが (この例では、?テキスト フィールドの検証が の場合でもボタンにフォーカスを当てることができますfalse)、私はまだ、ドキュメンテーションがすべての重要な副作用を説明する上で正確ではないという私の意見を保持しています。直観に反するため、ドキュメントを読むだけでなく、さらにテストと調査 (おそらくソース コードの分析) を行う必要があります。

4

1 に答える 1

2

doの呼び出しには効果があります。正確には、「このコンポーネントがフォーカスを要求する前に、現在のフォーカス所有者の入力ベリファイアが呼び出されるかどうか」を決定する効果です。[強調鉱山] 特に、次の状態を確立します。setVerifyInputWhenFocusTarget()

  • 初期statusText値のままにするか、有効な値を入力して初期値に戻します。

  • 無効な値を含んでいる間、フォーカスを与えたり持ったりtfFirstNumします。tfSecondNum

次に、それを観察します

  • ?変更されていない葉をクリックするstatusTextと、フォーカスされたコンポーネントの入力ベリファイアが呼び出されなかったことを意味します。

    btnHelp.setVerifyInputWhenFocusTarget(false);
    
  • StartセットをクリックしstatusTextてエラーを反映します。つまり、フォーカスされたコンポーネントの入力ベリファイア呼び出されたことを意味します。

    btnStart.setVerifyInputWhenFocusTarget(true);
    

いずれかのボタンをクリックしたときの効果を確認するには、上記の両方の条件が満たされている必要があることに注意してください。

于 2016-07-31T09:31:59.717 に答える