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

24 篇文章 0 订阅

控制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();
		}
	}
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值