回 帖 发 新 帖 刷新版面

主题:文本框 VS 编辑框

大家好,今天发个贴,希望对初学者或者FOX爱好者有帮助。

谈谈文本框和编辑框。

这两个东东我们经常用来在表单上显示数据或者接受用户输入,习惯上我们总是用编辑框输入大段文字或者绑定到备注字段,其他情况则用文本框。一般说来完全没问题,但凡事总有例外,比如某种情况下,我们要从文本框得到输入的字符,特别是希望得到输入字符串中到底有多少个空格,对于前导空格和字符中间的空格来说,那是轻而易举的,糟糕的是,您无法知道字符串有多少个尾随空格。文本框有个坏脾气,不管372十1总在后面加入空格用以占满整个文本框的输入区域,因此您即便什么都没输入,它的Value也是一串空格。您可以用?Len(thisform.text1.value)看看。在这种情况下,我们只有对空格采取歧视的态度,我们总规定在文本框中输入字符串时不要有尾随空格,或者说希望输入的字符串本身不要尾随空格。您常常见到用ALLTRIM()处理文本框的VALUE,这把前导空格也一并干掉。

空格也是字符,我要一视同仁,那么用编辑框代替。
编辑框很有意思,当您把它的高度弄得只能显示一行字符时,这家伙就表现的像个文本框,您输入一些字符,按回车键,它不会在下面重起一行,而是像文本框一样丢掉焦点。更重要的是这家伙的VALUE属性如实地记录您键入的字符(有几个字符、是什么字符),您输入的空格和其他字符一样平等对待,您真想获取真实输入的字符串,直接取它的VALUE而无需处理。

这里说说密码输入框的问题,如果用文本框,则无法很好得把空格作为密码字符的一部分(空格为什么不能做密码),如果一个密码是“ABC  ”(后面两个空格),文本框是无法知道您到底键入了几个空格。改用编辑框就行,只要设置passwordchar属性,比如常见的*号,棒极了!

有人说:等等,有个问题,其它字符都很好,我是说都显示*号,空格却还是显示空格。

是的,看来编辑框处理密码也排斥空格,不过不难解决。

下一帖谈谈NODEFAULT与键盘击键的改写技术,顺便解决今天遗留的问题。

回复列表 (共8个回复)

沙发

NODEFAULT与击键的改写

今天谈谈这个话题,就是想达到这样一种效果:某种条件下,在文本框或编辑框中输入数据时,根据某种要求,把按下的键变成另外一个键。比如说:键入一个小写字母a,变成一个大写字母A,或者只允许输入数字(其它字符被取消)。

有人说:唉,这有什么,利用Format属性和InputMask属性就能做到。比如你说的键入a,变成A,只需给Format属性设置一个叹号(!)就行。

对,很好。不过先看个例子,我想键入A,显示a,即键入大写字母,转为小写字母。怎么办?

有人又说:多此一举,一般情况下,键盘总是小写输入的。

好吧!你对,不过我还是继续说下去。

当我们按键时,会触发文本框或者编辑框的KeyPress事件,该事件包含参数nKeyCode和nShiftAltCtrl,前一个代表你按下的键,后一个是你组合键Shift、Alt、Ctrl的状态。这个事件提供了对键盘的截获能力。现在我们要按某种需要处理按键,就比如把大写字母改为小写字母,首先要告诉系统放弃键入的大写字母,然后修改键码再通知系统继续。怎么做?

介绍一下NODEFAULT命令,这个命令出现在事件代码或方法代码中时,告诉系统不要用默认的方式处理,比如对于按键,系统默认的处理方式就是按照键码该显示的显示、该进行某种操作的就进行操作。如果事件中执行了NODEFAULT,那就相当于屏蔽了后续处理。

再介绍一下DODEFAULT()函数,该函数通知系统按默认方式处理事件。注意它往往需要参数,而参数就是该函数所位于的事件代码的参数。

现在好了,有了这两个家伙的作用,我们编程实现文本框TEXT1键入大写字母变为小写

LPARAMETERS nKeyCode, nShiftAltCtrl
IF nKeyCode>=65 AND nKeyCode<=90      &&大写字母
  NODEFAULT                           &&屏蔽默认处理
  nKeyCode=nKeyCode+32                &&修改键码为小写
  nShiftAltCtrl=0                     &&屏蔽组合
  DODEFAULT(nKeyCode, nShiftAltCtrl)  &&通知系统按新的键码继续处理
ENDIF

再看一个例子,我想输入一个小写字母,结果变成它的下一个字母,例如输入a变成b,......输入z又变成a。

LPARAMETERS nKeyCode, nShiftAltCtrl
IF nKeyCode>=97 AND nKeyCode<=122     &&小写字母
  NODEFAULT                           &&屏蔽默认处理
  nKeyCode=97+(nKeyCode-97+1)%26      &&修改键码为下一个
  nShiftAltCtrl=0                     &&屏蔽组合
  DODEFAULT(nKeyCode, nShiftAltCtrl)  &&通知系统按新的键码继续处理
ENDIF

以上介绍只是特殊情况下的处理办法,KeyPress也不能截获所有键盘事件(例如Ctrl+C、Ctrl+V)。您可以举一反三,当然也可以不用它。

现在处理上贴中说到的用编辑框作为密码框时,空格的显示问题。
因为即使设置了PasswordChar属性,空格依然会显示为空格而不是*,好,我们利用keyPress事件对空格处理一下
LPARAMETERS nKeyCode, nShiftAltCtrl
IF nKeyCode=32                        &&空格
  NODEFAULT                           &&屏蔽默认处理
  this.seltext=chr(7)                 &&用一个控制字符代替空格
ENDIF

KeyPree参数nKeyCode为32,表示键入一个空格,我们屏蔽它,接下来不用改写键码(改成哪个都不合适,你怎么知道你改的恰恰不是密码本身就有的字符),用个控制字符chr(7)来代替(原本它是让扬声器“嘟”一声,这里不会),可是键码(参看INKEY()函数键码表)中不包含该字符,于是我们直接用selText属性加入到密码框。好了,键入空格也是*号表示了。不过,后面取出Value值时要处理一下才对,用STRCHAN()函数把所有chr(7)字符还原为空格即可。

这里忽然想起“有约故人来”网友提出“修改已有数值的文本框能否直接覆盖原文本框的数值”的问题,用NODEFAULT可以解决。仍旧如qjbzjp网友所说,设置属性SelectOnEntry= .T.,不过在mousedown事件中多加一句NODEFAULT。本来鼠标单击时默认处理是使文本框得到焦点然后进一步设置selstart属性为鼠标指针点击的位置,这个NODEFAULT屏蔽了后面那一步默认处理,效果就是单击文本框,会选中全部内容。当然这不完美,如果只是简单的一句NODEFAULT,无论怎么单击文本框都会全选,万一只想在某个位置插入一点东西怎么办。理想的效果是,第一次单击文本框,全选中。只要焦点不离开,后面就能单击移动光标到文本框数据字串的任何位置。焦点离开文本框下次再单击,又重复刚才的效果。

做法如下:
文本框设置属性SelectOnEntry= .T.

mousedown事件
LPARAMETERS nButton, nShift, nXCoord, nYCoord
IF this.SelectOnEntry 
   NODEFAULT
ENDIF

CLICK事件
this.SelectOnEntry=.F.

LostFocus事件
this.SelectOnEntry=.T.

OK,行了。

下一帖谈谈透明控件的妙用,再次就“有约故人来”网友提出的问题给出另一种解决办法。

板凳

改个错误:
不过,后面取出Value值时要处理一下才对,用STRCHAN()函数把所有chr(7)字符还原为空格即可。

STRCHAN() 改为 STRTRAN() 手误,呵呵。

3 楼

谢谢赵先生,拜读了!

4 楼

jinlonggao先生好,只是些小技巧,您说拜读,不敢当啊!

透明控件的妙用

有许多控件可以设置BackStyle属性为0(透明),比如Shape Container Label等等,设置透明一般为了满足某种视觉需要。比如标签Label常常设置透明,为了让它透出表单的颜色,显得它显示的文字就像直接在表单上写出来的一样,同样也为了防止它部分遮住其它的控件。

今天特地谈谈形状控件Shape,这里不是让它来显示一个矩形或是椭圆,而是让它透明,并且连边框BoardStyle属性也设置为0。这样一来,运行时完全感觉不到它的存在。但是它确实存在,如果你编写了它的某种事件(比如Click)代码,并且你也知道它在哪个位置,向那个位置单击,就要执行代码了。仅就这一点,就可以利用来作点秘密的事情,可以用来编写一些恶作剧,当然这里不谈这个。

我要说的是,把这个完全透明的Shape覆盖在其它控件上会有什么效果。比如我把它覆盖在一个按钮上(完全盖住),运行时只看到按钮,单击按钮,哈,没反应。当然是这样,因为其实单击的是那个透明的Shape。

好了,现在再来就“有约故人来”网友提出的问题给出一种解决办法。
问题就是有个文本框,希望第一次单击它选中里面的全部文字,在焦点没有离开这个文本框时,后续操作就如同常规情况一样。

我们用一个透明Shape完全盖住文本框,在Shape的Click事件里让它下面的文本框得到焦点,这时我们要让Shape消失,为了不影响文本框操作,当离开文本框时,我们让Shape再次出现(呵呵,消失、出现都看不到)。
做法如下:
文本框设置属性SelectOnEntry= .T.

Shape的Click事件代码
thisform.text1.SetFocus 
this.Visible=.F.

文本框的LostFocus事件代码
thisform.shape1.Visible=.T.

OK,行了。注意一点,Shape应置于Text的前方。

5 楼

深出隐居半年后,采了灵芝来普渡众生了!

6 楼

呵呵,楼上好,乱发一些,见笑。
正则表达式简介

先看个例子:
有一个字符串"13912345678发短信给15009876543祝贺生日13500001234收到13411223344的彩信"。编程获取所有的手机号。
对于这样的问题,AT(),Occurs()等等都没什么用处,似乎只能一个一个取出字符判断。

cText="13912345678发短信给15009876543祝贺生日13500001234收到13411223344的彩信"
FOR I=1 TO LEN(cText)
  cChr=SUBSTR(cText,I,1)   &&从头开始一个一个取字节
  IF ISDIGIT(cChr)         &&只要是数码,立刻取出该位置开始的11个数码
    ?SUBSTR(cText,I,11)
    I=I+10                 &&修改循环控制变量,使I下次循环时跨越10个字节
  ENDIF
ENDFOR

嗯,很好,尽管稍稍麻烦了一点,但做到了。改一下字符串为"13912345678发短信给15009876543祝贺18岁生日13500001234收到13411223344的彩信"。瞧,“生日”前仅仅多了“18岁”,上

面的程序就要出问题了。气煞我也,再改程序:

cText="13912345678发短信给15009876543祝贺18岁生日13500001234收到13411223344的彩信"
FOR I=1 TO LEN(cText)
  cChr=SUBSTR(cText,I,1)
  IF ISDIGIT(cChr)               &&遇到一个数码
    lIsPhoneNum=.T.              &&假设是手机号,变量lIsPhoneNum为真
    FOR J=1 to 10                &&判断后面10个字符是不是数码
      IF !isDigit(SUBSTR(cText,I+J,1))   &&只要有一个不是就使lIsPhoneNum为假并退出循环
        lIsPhoneNum=.F.
        EXIT
      ENDIF   
    ENDFOR
    IF lIsPhoneNum
      ?SUBSTR(cText,I,11)
      I=I+10
    ENDIF
  ENDIF
ENDFOR

哈哈,成了。不过麻烦了许多。有没有快捷方便的办法来做这个事,有,正则表达式计算。

不管372十1,先看看利用正则表达式编写的程序:

cText="13912345678发短信给15009876543祝贺18岁生日13500001234收到13411223344的彩信"
oRegExp=NEWOBJECT("_RegExp",HOME(1)+"Ffc\_RegExp.vcx")   &&生成正则表达式对象
oRegExp.pattern="\d{11}"                                 &&设立模式
n=oRegExp.execute(cText,.F.)                             &&执行搜索,返回找到的数目
IF n>0
  FOR I=1 to n
    ?oRegExp.matches(I,2)                                &&输出找到的字符串
  ENDFOR
ENDIF

OK,行了。试试看。

下面来说说所谓的正则表达式,不过我们先来搜索文件。
什么?干嘛先来搜索文件,这和正则表达式有关吗?
呵呵,关系不大,不过有类似的地方。我们要找的文件名为:第1字符是c,后面接任意字符,扩展名的前两个字母是fr,最后一个任意。这简单,用通配符来做,写成“c*.fr?”。对极了,

你使用通配符*表示任意多个任意字符,用?表示任意的一个字符。
正则表达式也是这样,它提供“通配符”表示字符,不过它的“通配符”要复杂的多。比如\d就代表是一个数码,[a-z]就代表一个小写字母,甚至[^h]代表一个不是"h"的字符,而*和?在正

则表达式里具有不同的含义,比如a*表示字符a或者不存在或者有多个而a?表示字符a或者有或者没有,呵呵,晕了吧,还有更多功能强大但又复杂的通配符。要讲清楚这些不是一时半会的事

情,俺就跳过。
正则表达式就是由这些“通配符”构成的字符串(术语称为“模式”--pattern),由于它表示的含义非常丰富,在字符串搜索中具有强大的优势。不过学习正则表达式最大的难点也就是如何

构造所需要的模式,这个需要多看些例子了(呵呵,互联网上大大的有)。
上面程序利用了VFP提供的正则表达式类_RegExp.vcx,其实是对VBScript.RegExp的封装。我们设置的正则表达式"\d{11}",\d代表是一个数码,{11}表示前面的字符重复11次。执行execute

方法,就会拿pattern在第一参数中搜索(第二参数表示大小写敏感,这里用不上,给个假值)。找到的结果放在matches属性中,这是一个二维数组,第一列是找到的位置(特别注意,由于实际

上是VBScript.RegExp对象实现的,它把双字节汉字看作一个字符);第二列就是找到的符合模式的字符串。

就说这么多吧。I Like Fox,尽管它在老去。

7 楼

今天继续发贴,希望对初学者或者FOX爱好者有帮助。

改造对象的方法

先看例子:请在表单(40,50)的坐标位置以60为半径画个圆。这很简单,调用Circle方法,1句代码就实现了。
thisform.Circle(60,40,50)

好,加点条件,圆是红色的。嗯,也不难。
thisform.ForeColor=RGB(255,0,0)
thisform.Circle(60,40,50)

多加1条语句,改变表单的前景色。要是画多个不同颜色的圆,类似的两句要来回出现。这时,我有个想法,能不能把颜色值直接作为Circle方法的参数,这样一来就不用考虑ForeColor属性。

行,那要对Circle方法改造改造。

我们在代码窗口找到Circle方法,哈,系统帮我们来了一句
LPARAMETERS nRadius, nXCoord, nYCoord

看来可以编写自己的语句了,我们写成下面的样子(注意:下面是不对的)

LPARAMETERS nRadius, nXCoord, nYCoord, nColor   &&追加参数nColor
NODEFAULT
thisform.ForeColor=nColor
DODEFAULT(nRadius, nXCoord, nYCoord)

呵呵,运行会出错。介四怎么回四??
其实系统帮我们写的那句有问题,看看Help就知道,原来还有第4参数nAspect,因此写成

LPARAMETERS nRadius, nXCoord, nYCoord, nAspect, nColor   &&追加参数nColor
NODEFAULT
thisform.ForeColor=nColor
DODEFAULT(nRadius, nXCoord, nYCoord, nAspect) 

改造完成。
我们用一句
thisform.Circle(60, 40, 50, , RGB(255,0,0)) &&注意有个参数置空了,这里用不上
就能实现画出一个红色的圆。

有人说,何必呢,我写个自定义的方法比如MyCircle,代码和你差不多,不也行嘛。
自定义thisform.MyCircle方法:
LPARAMETERS nRadius, nXCoord, nYCoord, nAspect, nColor
thisform.ForeColor=nColor
thisform.Circle(nRadius, nXCoord, nYCoord, nAspect) 

您是对的,如果我非要狡辩,那只能嚷嚷说,从对象的组成来看,我至少比你少一个成员,呵呵。

这个帖子仅仅说明一种途径,供开阔思路而已。

8 楼

顶上来,学习了

我来回复

您尚未登录,请登录后再回复。点此登录或注册