How to set a Mask to a SWT Text to only allow Decimals

吃可爱长大的小学妹 提交于 2019-11-28 09:09:07

问题


What I want is that the user can only input decimal numbers on a Text, I don't want it to allow text input as:

  1. HELLO
  2. ABC.34
  3. 34.HEY
  4. 32.3333.123

I have been trying using VerifyListener, but it only gives me the portion of the text that got inserted, so I end up having the text that I want to insert and the text before the insertion, tried also combining the text, but I got problems when you delete a key (backspace) and I end up having a String like 234[BACKSPACE]455.

Is there a way to set a Mask on a Text or successfully combine VerifyEvent with the current text to obtain the "new text" before setting it to the Text?


回答1:


You will have to add a Listener on the Text using SWT.Verify. Within this Listener you can verify that the input contains only a decimal number.

The following will only allow the insertion of decimals into the text field. It will check the value each time you change something in the text and reject it, if it's not a decimal. This will solve your problem, since the VerifyListener is executed BEFORE the new text is inserted. The new text has to pass the listener to be accepted.

public static void main(String[] args) {
    Display display = Display.getDefault();
    final Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());

    final Text textField = new Text(shell, SWT.BORDER);

    textField.addVerifyListener(new VerifyListener() {

        @Override
        public void verifyText(VerifyEvent e) {

            Text text = (Text)e.getSource();

            // get old text and create new text by using the VerifyEvent.text
            final String oldS = text.getText();
            String newS = oldS.substring(0, e.start) + e.text + oldS.substring(e.end);

            boolean isFloat = true;
            try
            {
                Float.parseFloat(newS);
            }
            catch(NumberFormatException ex)
            {
                isFloat = false;
            }

            System.out.println(newS);

            if(!isFloat)
                e.doit = false;
        }
    });

    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
        if (!display.readAndDispatch())
            display.sleep();
    }
}



回答2:


Have you tried the FormattedText Widgets from Nebula? - They are an easy way to implement these kind of input fields, see http://eclipse.org/nebula/widgets/formattedtext/formattedtext.php




回答3:


In order to get the behavior that I wanted I had to use several listeners:

  • A VerifyListner restricts the characters that are accepted as partial input while typing
  • A FocusListener validates the total input when leaving focus. If the total input is not valid, an error decoration will be shown.
  • A ModifyListener checks if the error decoration can be hidden while typing. It does not show the error decoration since invalid partial input like "4e-" is allowed to finally enter "4e-3"

    valueField.addVerifyListener((event) -> restrictInput(event));
    valueField.addModifyListener((event) -> validateValueOnChange(valueField.getText()));
    
    valueField.addFocusListener(new FocusListener() {
        @Override
        public void focusGained(org.eclipse.swt.events.FocusEvent e) {}
        @Override
        public void focusLost(org.eclipse.swt.events.FocusEvent event) {
            validateValueOnFocusLoss(valueField.getText());
        }
    });
    
    protected void restrictInput(VerifyEvent event) {
        String allowedCharacters = "0123456789.,eE+-";
        String text = event.text;
        for (int index = 0; index < text.length(); index++) {
            char character = text.charAt(index);
            boolean isAllowed = allowedCharacters.indexOf(character) > -1;
            if (!isAllowed) {
                event.doit = false;
                return;
            }
        }
    }
    
    protected void validateValueOnChange(String text) {
        try {
            Double.parseDouble(valueField.getText());
            valueErrorDecorator.hide();
        } catch (NumberFormatException exception) {
            //expressions like "5e-" are allowed while typing
        }
    }
    
    protected void validateValueOnFocusLoss(String value) {
        try {
            Double.parseDouble(valueField.getText());
            valueErrorDecorator.hide();
        } catch (NumberFormatException exception) {
            valueErrorDecorator.show();
        }
    }
    

The ModifyListener could be further improved to check for partial input that is not able to finally give a valid total input, e.g. "4e-....3". In that special case the ModifyListener should activate the error decoration while typing.




回答4:


In addition to @Tom Seidel's answer:
You could use a org.eclipse.swt.widgets.Spinner. This allows only digits. You can specify min and max value and the return value is an int so no need to cast a String.

final Composite composite parent = new Composite(superParent, SWT.NONE);
parent.setLayout(new FillLayout());
final Spinner spinner = new Spinner(parent, SWT.BORDER);
spinner.setvalues(0, 10, Integer.MAX_VALUE, 0, 1, 10);

The value of the Spinner can than be retrieved by calling:

int selectedValue = spinner.getSelection();


来源:https://stackoverflow.com/questions/11831927/how-to-set-a-mask-to-a-swt-text-to-only-allow-decimals

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!