java SWT:限制数值输入的Text文本框通用组件

时间:2022-06-22
本文章向大家介绍java SWT:限制数值输入的Text文本框通用组件,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/53728943

控制Text只能输入数值只能输入数值的原理很简单,就是利用VerifyListener侦听器,响应VerifyEvent 事件,对输入内容进行检查。 具体如何验证输入的内容是有效数字,网上有很多文章介绍如何实现,有是检查输入字符是不是0-9,这种方式有局限性,有的是利用正则表达式来判断,写得好复杂。 其实利用Float,Integer,Double这些类的静态方法valeOf(String)就能准确进行检查,valeOf(String)方法将一个字符转为对应类型的数字,如果格式不对就会抛出NumberFormatException 异常。 利用这个特性,就可以很方便的对Text输入的内容进行有效性检查。 在这里有必要解释一下org.eclipse.swt.events.VerifyEvent事件类的成员变量的含义。 VerifyEvent有三个有用的成员变量:text,start,end:

start,end:是指当前事件中Text中文本字符串将被修改的起止范围 text:将被插入到start,end范围的文本字符串,(删除字符时text为空字符串)

有了这三个数据,用java.lang.StringBuffer就可以构造出事件发生后,Text文本的内容,然后就可以用valueOf方法来验证输入的数据是否有效。

下面是验证浮点数(Float)类型数值的实现代码。 NumText.java

package net.gdface.ui;

import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;

public class NumText extends Text {
    /**
     * Create the composite.
     * 
     * @param parent
     * @param style
     */
    public NumText(Composite parent, int style) {
        super(parent, style);
        this.addVerifyListener(new VerifyListener() {
            @Override
            public void verifyText(VerifyEvent e) {
                try {
                    // 以Text中已经输入的内容创建StringBuffer对象
                    StringBuffer buffer = new StringBuffer(NumText.this.getText());
                    // 删除e.start, e.end指定范围的内容
                    // 并将要插入的内容e.text插入指定的位置,模拟输入e.text后Text对象中的内容
                    // 末尾添一个0,以保证buffer中只有一个字符为且为+-.时,不会触发NumberFormatException 
                    buffer.delete(e.start, e.end).insert(e.start, e.text).append('0');
                    // 尝试将buffer中的内容转换成Float,如果不抛出异常说明输入内容有效
                    Float.valueOf(buffer.toString());
                } catch (NumberFormatException ex) {
                    e.doit=false;
                }
            }
        });
    }

    @Override
    protected void checkSubclass() {
        // Disable the check that prevents subclassing of SWT components
    }
}

更进一步,我们可以利用reflect技术,将上面的NumText 扩展成支持Float,Integer,Double,Long等类型的泛型类,并提供用户自定义的验证方法,以增强其通用性。

package net.gdface.ui;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;

/**
 * 泛型对象<br>
 * 实现数值文本限制的Text组件
 * @author guyadong
 *
 * @param <T> Text组件接收的数据类型,可为{@link Float},{@link Double},{@link Integer},{@link Long},{@link Byte},{@link Short}类型
 */
public class NumText<T extends Number> extends Text {
    /**
     * valueOf方法
     */
    private final Method valueOf;
    /**
     * toString()方法
     */
    private final Method toString;
    /**
     * 缺省值
     */
    private final T defaultValue;

    /**
     * Create the composite.
     * 
     * @param parent
     * @param style
     * @param defaultValue
     *            缺省值
     */
    public NumText(Composite parent, int style, T defaultValue) {
        super(parent, style);
        if (null == defaultValue)
            throw new NullPointerException();
        try {
            this.defaultValue = defaultValue;
            // 获取toString方法
            toString = defaultValue.getClass().getMethod("toString");
            // 调用toString给Text设置初始文本
            setText((String) toString.invoke(this.defaultValue));
            // 获取valueOf方法
            valueOf = defaultValue.getClass().getMethod("valueOf", String.class);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        addVerifyListener(new VerifyListener() {
            @SuppressWarnings("unchecked")
            @Override
            public void verifyText(VerifyEvent e) {
                // 以Text中已经输入的内容创建StringBuffer对象
                StringBuffer buffer = new StringBuffer(NumText.this.getText());
                // 删除e.start, e.end指定范围的内容
                // 并将要插入的内容e.text插入指定的位置,模拟输入e.text后Text对象中的内容              
                buffer.delete(e.start, e.end).insert(e.start, e.text);
                boolean appendZero=false;
                while(true){
                    try {
                        T v=(T) valueOf.invoke(null, buffer.toString());
                        if(appendZero)
                            v=(T) valueOf.invoke(null,"0");
                        // verify返回false则数据不合用户需求
                        if(!verify(v))
                            e.doit = false;
                        break;
                    } catch (InvocationTargetException ex) {
                        if (ex.getTargetException() instanceof NumberFormatException) {
                            if(!appendZero){
                                // 尝试末尾添一个0再解析,以保证buffer中只有一个字符为且为+-.时,不会触发NumberFormatException
                                buffer.append('0');
                                appendZero=true;
                                continue;
                            }
                            e.doit = false;
                            break;
                        }
                    } catch (IllegalAccessException | IllegalArgumentException ex) {
                        throw new RuntimeException(ex);
                    }
                }
            }
        });
    }
    /**
     * 子类可重写此方法以验证数据符合要求
     * @param v
     * @return 数值符合要求返回true
     */
    protected boolean verify(T v){
        return true;
    }
    @Override
    protected void checkSubclass() {
        // Disable the check that prevents subclassing of SWT components
    }

    /**
     * 获取Text组件中的数值<br>
     * 字符串解析抛出{@link NumberFormatException}时返回缺省值 {@link #defaultValue}
     * @return
     */
    @SuppressWarnings("unchecked")
    public T getValue() {
        try {
            return (T) valueOf.invoke(null, getText());
        } catch (InvocationTargetException ex) {
            if (ex.getTargetException() instanceof NumberFormatException) {
                return defaultValue;
            }
            throw new RuntimeException(ex);
        } catch (IllegalAccessException | IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * 设置Text组件中的数值
     * @param value
     */
    public void setValue(T value) {
        try {
            if (null == value)
                throw new NullPointerException();
            setText((String) toString.invoke(value));
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
}

相关的测试代码 Setting.java

package net.gdface.ui;

import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

public class Setting extends Dialog {

    protected Object result;
    protected Shell shell;
    private Text globalAspectRatioValue;
    private Text defaultRectSizeValue;
    private Text defaultAspectRatioValue;



    /**
     * Create the dialog.
     * @param parent
     * @param style
     */
    public Setting(Shell parent, int style) {
        super(parent, style);
        setText("SWT Dialog");
    }

    /**
     * Open the dialog.
     * @return the result
     */
    public Object open() {
        createContents();
        shell.open();
        shell.layout();
        Display display = getParent().getDisplay();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        return result;
    }

    /**
     * Create contents of the dialog.
     */
    private void createContents() {
        shell = new Shell(getParent(), SWT.DIALOG_TRIM);
        shell.setSize(588, 405);
        shell.setText(getText());

        TabFolder tabFolder = new TabFolder(shell, SWT.NONE);
        tabFolder.setBounds(10, 10, 572, 367);

        TabItem tbtmEditor = new TabItem(tabFolder, SWT.NONE);
        tbtmEditor.setText("矩形编辑器");

        Composite composite = new Composite(tabFolder, SWT.NONE);
        tbtmEditor.setControl(composite);

        Group group = new Group(composite, SWT.NONE);
        group.setBounds(22, 10, 243, 116);

        Button globalAspectRatioCheck = new Button(group, SWT.CHECK);

        globalAspectRatioCheck.setSelection(false);
        globalAspectRatioCheck.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                globalAspectRatioValue.setEnabled(globalAspectRatioCheck.getSelection());
                defaultAspectRatioValue.setEnabled(!globalAspectRatioCheck.getSelection());
            }
        });
        globalAspectRatioCheck.setBounds(10, 16, 81, 17);
        globalAspectRatioCheck.setText("固定宽高比");

        globalAspectRatioValue = new NumText<Float>(group, SWT.BORDER,0f){

            @Override
            protected boolean verify(Float v) {
                // 重写verify方法,验证数据有效性
                return v>0;
            }};
        globalAspectRatioValue.setEnabled(false);
        globalAspectRatioValue.setBounds(150, 11, 73, 23);

        Label defaultAspectRatioText = new Label(group, SWT.NONE);
        defaultAspectRatioText.setBounds(10, 49, 61, 17);
        defaultAspectRatioText.setText("默认宽高比");

        defaultAspectRatioValue = new NumText<Float>(group, SWT.BORDER,0f){

            @Override
            protected boolean verify(Float v) {
                // 重写verify方法,验证数据有效性
                return v>0&&v<1;
            }};
        defaultAspectRatioValue.setBounds(150, 45, 73, 23);

        Label defaultRectSizeText = new Label(group, SWT.NONE);
        defaultRectSizeText.setBounds(10, 82, 72, 17);
        defaultRectSizeText.setText("默认矩形尺寸");

        defaultRectSizeValue = new NumText<Integer>(group, SWT.BORDER,1){

            @Override
            protected boolean verify(Integer v) {
                // 重写verify方法,验证数据有效性
                return v>0&&v<100;
            }};
        defaultRectSizeValue.setBounds(150, 79, 73, 23);
    }
        /**
     * Launch the application.
     * @param args
     */
    public static void main(String[] args) {
        try {
            Setting setting = new Setting(new Shell(),SWT.NONE);
            setting.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}