Ich versuche, die Textfeld Benutzereingaben mit javax.swing.InputVerifier
zu validieren und die Eingabe Validierung funktioniert wie erwartet, aber ich habe ein Problem in Bezug auf VerifyInputWhenFocusTarget
Eigenschaft.VerifyInputWhenFocusTarget -Eigenschaft hat keine Wirkung
Ich habe ein Etikett gemacht, um den Status anzuzeigen und überschrieben verify()
und shouldYieldFocus()
Methoden der InputVerifier
Unterklasse und das funktioniert gut.
Der nächste Schritt, den ich tun wollte, war, die VerifyInputWhenFocusTarget
der Schaltfläche festzulegen, damit es den Fokus nicht erhalten würde, falls die Überprüfung des aktuellen Fokusbesitzers falsch war, aber ich bemerkte keinen Effekt der Einstellung der VerifyInputWhenFocusTarget
Eigenschaft auf true
und die Schaltfläche konnte gedrückt werden, auch wenn die Validierung des aktuellen Fokus Eigentümer falsch war.
Vielleicht verstehe ich nicht die Dokumente - ich dachte, die Einstellung der VerifyInputWhenFocusTarget
Eigenschaft der Schaltfläche true
würde verhindern, dass die Schaltfläche den Fokus erhalten, wenn unter den Umständen der falschen Validierung des Textfelds geklickt wird. Außerdem verstehe ich (falsch), wenn der Button den Fokus nicht bekommen konnte, würde seine actionPerformed()
Methode nicht aufgerufen werden.
Die Schaltfläche kann jedoch angeklickt werden und ihre actionPerformed()
Methode wird trotzdem von der falschen Validierung der Textfeld (e) 'bewacht' von javax.swing.InputVerifier
ausgeführt. Hier
ist das abgestreifte 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;
}
}
}
Und hier ist der Screenshot der Testanwendung:
Wie man sehen kann, gibt es zwei Tasten. Einer von ihnen hat die VerifyInputWhenFocusTarget
-Eigenschaft auf true
und die andere hat die gleiche Eigenschaft auf false
gesetzt, aber es gibt keinen Unterschied, wenn die Schaltfläche unter der Bedingung der falschen Textfeldvalidierung geklickt wird. Die falsche Validierung kann durch Eingabe einer negativen Zahl oder einer Zahl mit mehr als 4 Dezimalziffern provoziert werden. Die InputVerifier
verhindert zwar, dass der Fokus auf das andere Textfeld übertragen wird, verhindert aber nicht die Aktivierung der Schaltfläche. Da es (zumindest für mich) keinen Sinn macht, könnte die Taste aktiviert werden, ohne zuerst den Fokus zu bekommen, es sollte keine Möglichkeit geben, das Start zu aktivieren! Schaltfläche, wenn die Textfeldvalidierungsmethode verify()
zurückgegeben false
.
EDIT:
Ich habe jetzt den Code verändern die trashgod Vorschlag (Konditionierung des aktivierten Zustand der starten Taste mit FocusListener
!) Aufzunehmen, und hier ist das Arbeitsbeispiel:
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);
}
}
}
Ich habe den Code der verify()
Methode leicht geändert, um den Fokus zu ändern, wenn nichts eingegeben wird (focusLost()
Methode überprüft, ob alle Textfelder einige Eingaben enthalten und überprüft auch, ob die Eingaben gültig sind, indem für jedes der Textfelder explizit verify()
aufgerufen wird).
Der Code benötigt natürlich einige kleinere Optimierungen (Tab-Reihenfolge, Aktualisierung des Status, ...), aber das ist nicht im Rahmen dieses Themas.
Fazit:
Obwohl VerifyInputWhenFocusTarget
Eigenschaft offenbar nützlich ist (? Hier im Beispiel der Taste Fokus auch bei Textfeld gewinnen kann (s) Validierung war false
), ich bin immer noch mit angehaltenem Meinung die Dokumentation ist nicht ganz genau in der Beschreibung aller wichtigen Nebenwirkungen, die eher nicht intuitiv sind, so dass es notwendig ist, weitere Tests und Untersuchungen (vielleicht die Analyse des Quellcodes) neben nur das Lesen der Dokumente.
Klicken Sie auf "Start!" setzt 'statusText', um einen Fehler zu reflektieren, was bedeutet, dass der Eingabefilter der fokussierten Komponente tatsächlich aufgerufen wurde - aber falsche valitation hat ** nicht ** verhindert, dass die Schaltfläche den Fokus erhält/aktiviert wird. Auf der anderen Seite verhindert die falsche Validierung ** den Fokus im Fall eines Textfelds. Ich finde ein solches Verhalten inkonsistent, aber was noch wichtiger ist, wäre die Verwendung des 'InputVerifiers', wenn ** alle ** der Textfelder ** noch einmal ** validiert werden müssen, um die Schaltfläche zu aktivieren/deaktivieren oder um den Code innerhalb der Schaltfläche "actionPerformed" zu überspringen? –
Aus den Oracle-Dokumenten für 'setVerifyInputWhenFocusTarget()': 'Auf Komponenten wie eine Cancel-Schaltfläche oder eine Bildlaufleiste auf false setzen **, die auch dann aktiviert werden sollte, wenn die Eingabe im aktuellen Fokuseigner nicht vom Eingabeverifizierer "übergeben" wird ** für diese Komponente.Wenn dies der Zweck ist, dann ist das Gegenteil der Fall: "Setzen Sie auf ** ** ** ** ** auf Komponenten wie ** Start ** -Schaltfläche, die ** nicht ** aktiviert werden soll, wenn die Eingabe im aktuellen Fokus-Besitzer nicht ist vom Input-Verifier für diese Komponente "übergeben". Aber "das Gegenteil" (auf "wahr" gesetzt) verhindert ** nicht, dass die Schaltfläche aktiviert wird. –
Verwenden Sie einen separaten ['FocusListener'] (https://docs.oracle.com/javase/8/docs/api/java/awt/event/FocusListener.html), um den aktivierten Zustand von' btnStart' zu aktivieren; Sie können 'txtVerifier.verify()' wie erforderlich aufrufen, um den korrekten Status zu ermitteln. – trashgod