QUI界面不再卡死
本文由按键学院提供技术支持
零基础学按键精灵群(2群):372671254
原因引用
QUI界面事件如果添加循环命令,或者延时命令。添加之后,我们再去点击QUI界面,就会出现卡死的现象。
QUI界面事件:
窗口事件以及控件事件统称为界面事件。 界面事件?
按键精灵是怎么知道我们点击了哪个控件,鼠标移动到了界面的哪里了呢?
其实,我们看似平常的一个操作,
例如:移动鼠标到窗口界面上点击输入框。
这样的一个操作,其实是被分解成了几百条消息反馈给按键精-灵程序,告诉它鼠标现在在哪里,做了什么,点击了控件,然后控件要响应什么操作等等。
而这些消息,按键精-灵程序会逐条处理,处理完这一条才会继续处理下一条。
所以,当它在处理循环事件会延时事件时,没有处理完之前都不处理其它信息。
使用循环命令导致界面卡死的解决方法1、多线程 界面上有两个控件,输入框1(InputBox1)和按钮1(Button1)
当按下按钮1(Button1)时, 启动线程,将延时命令和循环命令放在线程里执行。循环一百次给输入框赋值。
代码:- Event Form1.Button1.Click
- BeginThread 循环 //启动线程
- End Event
- Sub 循环
- For i = 1 To 100
- Delay 200
- Form1.InputBox1.Text = "" & i
- Next
- End Sub
2、定时器 定时器的有效设置为否
时间间隔设置为200毫秒(执行一次循环需要的时间)
当按下按钮1(Button1)时,将定时器的有效设置为是( Form1.Timer1.Enabled = True) 定时器每隔200毫秒会执行一次 Timer 事件
我们在 Timer事件中,定义一个变量i,每执行一次 Timer时间i的值叠加1,直到i的值等于我们设置循环次数,则将定时器的有效设置为否。
代码:- Event Form1.Button1.Click
- Form1.Timer1.Enabled = True
- End Event
- Event Form1.Timer1.Timer
- i = i + 1
- If i= 100 then Form1.Timer1.Enabled=False
- Form1.InputBox1.Text = "" & i
- End Event
3、API函数 引用
我们已经知道了,界面卡住,是因为在处理循环命令时,产生了其它的消息导致的。
那么我们可以这样做,当在执行循环命令时,界面上的其它所有消息都忽略掉,不反馈给按键精灵程序。
要用到四个Api函数:LocalAlloc、PeekMessageA、TranslateMessage、 DispatchMessageA、LocalFree
代码:- Declare Function PeekMessageA Lib "user32.dll" Alias "PeekMessageA"(ByVal 消息格式 As Any,ByVal 窗口句柄 As Long,ByVal 消息最小过滤值 As Long,ByVal 消息最大过滤值 As Long,ByVal 删除消息 As Long) As Long
- Declare Function LocalAlloc Lib "kernel32" Alias "LocalAlloc" (ByVal wOemChar As Long,ByVal wOmChar As Long) As Long
- Declare Function LocalFree Lib "kernel32" Alias "LocalAlloc" (ByVal hMem As Long) As Long
- Declare Function TranslateMessage Lib "user32.dll" Alias "TranslateMessage"(ByVal 消息结构 As Any) As Long
- Declare Function DispatchMessageA Lib "user32.dll" Alias "DispatchMessageA"(ByVal 消息结构 As Any) As Long
- Event Form1.Button1.Click
- For i=1 to 100
- Form1.InputBox1.Text = "" & i
- call 处理事件
- Next
- End Event
- Sub 处理事件()
- WM=LocalAlloc (0,28) //分配一块存储空间用于存放消息
- If PeekMessageA(WM, 0, 0, 0, 1) <> 0 Then //获取当前程序的消息存放在 "消息结构"里,然后将消息删除,忽略不处理
- TranslateMessage WM //将空消息转换成程序可识别格式(虚拟键消息转换为字符消息)
- DispatchMessageA WM //将转完格式的空消息反馈给程序
- End If
- LocalFree WM //释放存储空间
- End Sub
使用延时命令导致界面卡死的解决方法 API函数 引用
当我们的延时命令不是放在多线程里,也不是靠定时器来处理,一定要放在QUI事件中时,该怎么办呢?
我们用上面说到的Api函数忽略消息的方法外加一个API函数:GetTickCount
来模拟一个在QUI界面事件中可执行的延时命令。
函数:GetTickCount:GetTickCount返回从操作系统启动所经过的毫秒数 步骤:我们先获取一次操作系统启动经过的毫秒数,放到变量s中
然后循环再次获取操作系统启动经过的毫秒数,如果小于我们设定的延时,就继续忽略消息,如果达到延时数则继续下一条循环。
代码:- Declare Function PeekMessageA Lib "user32.dll" Alias "PeekMessageA"(ByVal 消息格式 As Long,ByVal 窗口句柄 As Long,ByVal 消息最小过滤值 As Long,ByVal 消息最大过滤值 As Long,ByVal 删除消息 As Long) As Long
- Declare Function LocalAlloc Lib "kernel32" Alias "LocalAlloc" (ByVal wOemChar As Long,ByVal wOmChar As Long) As Long
- Declare Function LocalFree Lib "kernel32" Alias "LocalAlloc" (ByVal hMem As Long) As Long
- Declare Function TranslateMessage Lib "user32.dll" Alias "TranslateMessage"(ByVal 消息结构 As Long) As Long
- Declare Function DispatchMessageA Lib "user32.dll" Alias "DispatchMessageA"(ByVal 消息结构 As Long) As Long
- Declare Function GetTickCount Lib "kernel32" Alias "GetTickCount"() As Long
- Event Form1.Button1.Click
- For i = 0 To 10
- Form1.InputBox1.Text=""&i
- call 超级延时 (200)
- Next
- End Event
- Sub 超级延时(毫秒)
- Dim s
- s = GetTickCount()
- Wm=LocalAlloc(0,28)
- While (GetTickCount() - s < 毫秒)
- If PeekMessageA(Wm, 0, 0, 0, 1) <> 0 Then //得到消息
- TranslateMessage Wm
- DispatchMessageA Wm
- End If
- Wend
- LocalFree Wm
- End Sub
注意: 使用API函数忽略消息有个弊端,那就是当我们忽略消息的过程中,如果我们关闭了窗口,那只是假关闭。窗口的关闭是操作系统处理响应的,而关闭窗口之后要触发的一些操作,例如销毁进程、释放内存空间等等,都是程序本身在执行。但是程序被关闭时的状态是忽略处理消息的状态,关闭窗口要触发的操作被忽略掉了。
所以看上去窗口被关闭了,实际上窗口还在运行中。
本文由按键学院提供技术支持
【招生】主流回合制常见功能网络辅助教学——你懂得!
[ 此帖被mimi_rice在2015-02-25 13:23重新编辑 ]