找回密码
 加入
搜索
查看: 24494|回复: 32

[系统综合] 练习002 - 使Input控件只能输入特定范围内的数字

 火... [复制链接]
发表于 2010-1-2 17:57:46 | 显示全部楼层 |阅读模式
本帖最后由 pusofalse 于 2010-2-26 23:38 编辑

出题目的:
1、认识Windows消息的传递流程。
2、如何处理截取到的消息。

题解:
如题目所说,用GUICtrlCreateInput创建一个input输入框,使其只能输入数字,并且只能在1-50之间。以下是不合法的情况举例:

A_b2.# —— 字母、数字、特殊字符的任意组合。
010 —— 首位为0。
51、1001—— 不在1-50范围内。

要求:
1、禁止生成任何临时文件,禁止调用任何第三方。
2、无。

拓展:
如果完成了上述基础要求,再使input输入框有如下特性:
0、同是在1-50之间的数字。
1、用户在输入某个不合法的字符时(如字母a)或数字超出范围时,在输入那一刻(一刻——时长为无限短),使其不会在input框中显示,而是直接阻止输入(注,之前已经输入的合法字符不能删除,类似“日期和时间 属性”中的显示时间的input控件,在输入“25”时只会显示“2”,输入“5”时,没有任何反应,“5”在输入的那一刻,并没有在输入框中显示出来再删除掉,即,不会存在闪屏现象)。
2、使用ControlSetText、ControlSend、ControlGetText设置、读取input框内容时,编程使这3个函数运行失败,即不能设置读取到任何内容,input中的内容只能用物理输入。(类似某些游戏的输入框,不能使用ControlSend一样的情况)。
3、禁止输入框的粘贴、剪切功能。
4、除上述3点之外,使input框的其他特性不受影响。

加分:
视思路加分,20-90分不等。
1、如果完成基础要求,分值20-30。
2、如果完成拓展中的全部要求,分值70-90。
发表于 2010-1-2 19:24:45 | 显示全部楼层
#include <WinAPI.au3>
 
If not IsDeclared("WM_CHAR") Then CONST $WM_CHAR = 0x102
If not IsDeclared("WM_PASTE") Then CONST $WM_PASTE = 0x302
If not IsDeclared("WM_SETTEXT") Then CONST $WM_SETTEXT = 0xc
 
$hGUI = GUICreate("Test", 200, 100)
 
$iIptTest = GUICtrlCreateInput("", 20, 20, 160, 20)
$hIpt = GUICtrlGetHandle(-1)
 
$hIptProc = DllCallbackRegister("_IptProc", "int", "hWnd;uint;wparam;lparam")
$pIptProc = DllCallbackGetPtr($hIptProc)
$hOldProc = _WinAPI_SetWindowLong($hIpt, -4, $pIptProc)
 
GUISetState()
 
Do
Until guiGetMsg() = -3
 
 
Func _IptProc($hWnd, $iMsg, $wParam, $lParam)
    ConsoleWrite("0x" & Hex($iMsg) & @CRLF)
    If $iMsg = $WM_CHAR Then
                ;若限制只能输入英文和数字,把$wparam < 128 改为StringRegExp(Chr($wparam), "[0-9a-zA-Z]") = 0
        If $wparam <> 8 And StringRegExp(Chr($wparam), "[0-9a-zA-Z]") = 0 Then
            _WinAPI_MessageBeep(2)
            Return False
        EndIf
    ElseIf $iMsg = $WM_PASTE Then
        If StringRegExp(ClipGet(), "[\x20-\x7f]") Then Return False
    ElseIf $iMsg = $WM_SETTEXT Then
        _WinAPI_MessageBeep(2)
        Return False
    EndIf
    Return _WinAPI_CallWindowProc($hOldProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc    ;==>_IptProc()
这是以前论坛里前辈发的收藏的,呵呵,稍微测试了一下,退出又点问题

评分

参与人数 1金钱 +5 收起 理由
pusofalse + 5 感谢参与

查看全部评分

 楼主| 发表于 2010-1-2 19:30:56 | 显示全部楼层
本帖最后由 pusofalse 于 2010-1-2 20:04 编辑

回复 2# llztt


    感谢llztt兄的参与,但收藏的就不要这么早就贴上来了。看到一次现成的代码,会容易产生思维定向。暂时屏蔽,等有其他确切方案之后再解除屏蔽,望理解。
发表于 2010-1-2 19:41:57 | 显示全部楼层
本帖最后由 llztt 于 2010-1-2 19:54 编辑

不好意思啊,呵呵,直接贴上确是不妥,有违开贴主旨了,我会下次注意了

关于主题,我想最难的事是如何截获(不是监听)按键的动作,这个除了API或第三方还真没见出其他办法,至于字符限制什么的倒简单多了,呵呵,收藏过两个关于按键的源码,用的关键代码都一样。。

关于数值要求的<50有些麻烦啊。大于100判断好弄,但<50这个什么时候判断呢,因为我们输入67时,先输入的肯定是6,若判断这个6小于50就return的话,肯定不对了吧。。。难道是在失去焦点或按提交按钮才判断是否小于50?
发表于 2010-1-2 19:46:17 | 显示全部楼层
基础的是不是这样?
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
$Form1 = GUICreate("Form1", 256, 105, -1, -1)
$Input1 = GUICtrlCreateInput("", 24, 40, 190, 21, BitOR($ES_AUTOHSCROLL,$ES_NUMBER))
GUICtrlSetLimit (-1,3,1) 
GUISetState(@SW_SHOW)
While 1
Sleep (10)
$Read = GUICtrlRead ($Input1)
IF StringIsDigit ($Read) = 0 Then GUICtrlSetData ($Input1,"")
IF StringLeft ($Read,2) <> 10 Then
IF StringLen ($Read) = 2 Then 
     IF $Read < 50 Then GUICtrlSetData ($Input1,"")
EndIf
Else
         IF $Read > 100 Then GUICtrlSetData ($Input1,"")
EndIf
        $nMsg = GUIGetMsg()
        Switch $nMsg
                Case $GUI_EVENT_CLOSE
                        Exit

        EndSwitch
WEnd

评分

参与人数 1金钱 +25 收起 理由
pusofalse + 25 感谢参与,学习了。

查看全部评分

发表于 2010-1-2 20:01:00 | 显示全部楼层
本帖最后由 lchl0588 于 2010-1-2 21:16 编辑

呵呵,AU3 偶是一只小小的菜鸟,不能和楼上的比,只交一个有片面的小小的作业吧:
Dim $a=InputBox("作业","请输入1到50","1到50","","",20,500,200,0)
if $a>1 And $a<50 Then
        If $a>1 & $a<50 Then
                MsgBox(0,"作业","恭喜你输对了",2)
        EndIf
        EndIf
你有你的表达方式 ,偶有最菜  最基础的写法 呵呵!!

评分

参与人数 1金钱 +15 收起 理由
pusofalse + 15 感谢参与。

查看全部评分

 楼主| 发表于 2010-1-2 20:01:28 | 显示全部楼层
抱歉,这个题目本身有问题。
我已经修改题目了,4# llztt兄、5# landays兄,让两位白白思考了,抱歉至极!
发表于 2010-1-2 20:22:25 | 显示全部楼层
本帖最后由 afan 于 2010-1-3 01:28 编辑

这个貌似只能截取系统消息再处理了
发表于 2010-1-2 22:43:00 | 显示全部楼层
东抄西拼,只能做到输入框不能用右键粘贴,不能能禁止键盘的快捷键,可以试下在当前GUI上注册CTRL + V 类的快捷键,但恐怕那样没意思了,并不是真正意义上的禁止.
代码有些乱七八糟,高手莫见笑!!!
#include <WindowsConstants.au3>
#include <Constants.au3>
#include <GuiMenu.au3>
#include <WinAPI.au3>

$Form1 = GUICreate("只能输入1-50示例", 334, 98, -1, -1, $WS_THICKFRAME, -1)
$Input1 = GUICtrlCreateInput("", 112, 32, 121, 21)
$wProcNew = DllCallbackRegister("_MyWindowProc", "ptr", "hwnd;uint;long;ptr")
$wProcOld = _WinAPI_SetWindowLong(GUICtrlGetHandle($Input1), $GWL_WNDPROC, DllCallbackGetPtr($wProcNew))
$DummyMenu = GUICtrlCreateDummy()
$ContextMenu = GUICtrlCreateContextMenu($DummyMenu)
$CommonMenuItem = GUICtrlCreateMenuItem("这是什么?", $ContextMenu)
GUISetState(@SW_SHOW)

While 1
        If _IsFocused($Form1, $Input1) And StringLen(GUICtrlRead($Input1)) > 2 Or test() Then
                GUICtrlSetData($Input1, StringLeft(GUICtrlRead($Input1), StringLen(GUICtrlRead($Input1)) - 1))
        EndIf
        $nMsg = GUIGetMsg()
        Switch $nMsg
                Case - 3
                        Exit

        EndSwitch
WEnd

Func _IsFocused($hWnd, $nCID)
        Return ControlGetHandle($hWnd, '', $nCID) = ControlGetHandle($hWnd, '', ControlGetFocus($hWnd))
EndFunc   ;==>_IsFocused

Func test()
        If StringLen(GUICtrlRead($Input1)) = 1 Then
                Return Not StringRegExp(StringRight(GUICtrlRead($Input1), 1), "^[1-9]+$")
        EndIf
        If StringLen(GUICtrlRead($Input1)) = 2 Then
                If Int(StringLeft(GUICtrlRead($Input1), 1)) > 5 Then
                        Return GUICtrlSetData($Input1, GUICtrlRead($Input1) & "")
                EndIf
                If Int(StringLeft(GUICtrlRead($Input1), 1)) = 5 Then
                        Return Not StringRegExp(StringRight(GUICtrlRead($Input1), 1), "^[0]+$")
                Else
                        Return Not StringRegExp(StringRight(GUICtrlRead($Input1), 1), "^[0-9]+$")
                EndIf
        EndIf
EndFunc   ;==>test

Func do_clever_stuff_with_clipboard($hWnd)
        Local $sData
        $sData = ClipGet()
        If @error Then Return 0
        $sData = StringUpper($sData)
        GUICtrlSetData(_WinAPI_GetDlgCtrlID($hWnd), $sData)
        Return 1
EndFunc   ;==>do_clever_stuff_with_clipboard

Func ShowMenu($hWnd, $nContextID)
        Local $iSelected = _GUICtrlMenu_TrackPopupMenu(GUICtrlGetHandle($nContextID), $hWnd, -1, -1, -1, -1, 2)
        Switch $iSelected
                Case $CommonMenuItem
                        ;..........
        EndSwitch
EndFunc   ;==>ShowMenu

Func _MyWindowProc($hWnd, $uiMsg, $wParam, $lParam)
        Switch $uiMsg
                Case $WM_PASTE
                        Return do_clever_stuff_with_clipboard($hWnd)
                Case $WM_CONTEXTMENU
                        If $hWnd = GUICtrlGetHandle($Input1) Then
                                ShowMenu($Form1, $ContextMenu)
                                Return 0
                        EndIf
                Case $WM_SETCURSOR
                        GUICtrlSetCursor(_WinAPI_GetDlgCtrlID($hWnd), 5)
                        Return 1
        EndSwitch
        Return _WinAPI_CallWindowProc($wProcOld, $hWnd, $uiMsg, $wParam, $lParam)
EndFunc   ;==>_MyWindowProc

评分

参与人数 1金钱 +40 收起 理由
pusofalse + 40 学习了。

查看全部评分

发表于 2010-1-2 22:44:53 | 显示全部楼层
我记得论坛之前有人发过可以禁止粘贴进去的代码,不过忘记收藏在哪里了,一时找不出来
发表于 2010-1-2 23:36:57 | 显示全部楼层
Opt("GUIOnEventMode", 1)
$GUI = GUICreate("", 300, 180)
GUISetOnEvent(-3, "main")
GUICtrlCreateLabel("输    入:", 30, 64, 60, 17)
$Input = GUICtrlCreateInput('', 95, 60, 175, 20)
GUISetState(@SW_SHOW, $GUI)

While 1
        $in = GUICtrlRead($Input)
        If StringRegExp($in, "\D|^[5-9][1-9]+$|^0+$|^[0-9]{3,3}+$") Then GUICtrlSetData($Input,StringTrimRight($in,1))
WEnd

Func main()
        Switch @GUI_CtrlId
                Case - 3
                        Exit
        EndSwitch
EndFunc   ;==>main
使用正则

评分

参与人数 2金钱 +45 收起 理由
nmgwddj + 20 牛。虽然没看明白
pusofalse + 25 学习了。

查看全部评分

发表于 2010-1-3 00:03:48 | 显示全部楼层
楼上的代码精悍
发表于 2010-1-3 00:30:39 | 显示全部楼层
东抄西拼,只能做到输入框不能用右键粘贴,不能能禁止键盘的快捷键,可以试下在当前GUI上注册CTRL + V 类的快捷 ...
ceoguang 发表于 2010-1-2 22:43


禁止ctrl+v
If ControlGetFocus ($Form1) = "Edit1" Then ClipPut ("")
 楼主| 发表于 2010-1-3 00:35:42 | 显示全部楼层
本帖最后由 pusofalse 于 2010-1-3 00:41 编辑

Re 9#:
粘贴对应的消息是WM_PASTE。

Re 11#:
学习了,资源占用方面有些问题,我这里运行后,CPU会飙到50%。

Re 13#:
ClipPut("")只是清空剪切板,而非真正意义上的阻止粘贴操作。

感谢3位的参与,3位的代码都有共同之处,都不是直接阻止非法字符的输入的,而是在输入之后,已经显示出来之时,再加以判断的。都会存在极细微的闪屏现象,用循环读取内容的方法绝非上策,也会存在这样的闪屏和效率、资源占用问题。解决方法是,在字符还没有显示出来之前(消息还没有传递到消息链终点之前),就应该得到input框中的内容将会是怎样的。

用户在框中输入字符时,发送的消息是WM_CHAR,此时字符还不会显示出来。
发表于 2010-1-3 15:42:18 | 显示全部楼层
2#的就是楼主发的!
楼主来帮忙解释下
If StringRegExp(ClipGet(), "[\x20-\x7f]") Then Return False
这里的
[\x20-\x7f]
是什么意思?
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-11-16 08:30 , Processed in 0.080411 second(s), 22 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表