分享好友 编程语言首页 频道列表

VB DoEvents用法

VisualBasic  2023-02-09 04:320
 VB6.0
Windows98
我要实现一个类似Windows复制(移动)文件时的提示窗体,耗时很长,且要求中断后能继续未完成的操作,不知使用DoEvents从长循环中跳出后,程序将从何处开始继续执行,是否是从DoEvents所在的Sub开始?(倔小孩)

事实上仅使用DoEvents,并不意味着从长循环中跳出。DoEvents只是允许用户选择其他按钮而已,不中断循环,不管用户如何操作,都继续执行 DoEvents后面的语句,即使用户按下了中断按钮,你的循环仍然在继续,甚至你关闭了窗体,程序仍然继续在后台运行。正确的中断处理是这样的:
1、建立一个全局或窗体变量bRun。
2、在启动循环前设置bRun为True。
bRun = True
While bRun And (....)
....
DoEvents
Wend
...
3、在中断按钮Click事件中加入代码:
bRun = False
4、在Form_Unload事件中加入代码:
bRun = False
这样一旦用户按下了中断按钮,bRun = False,循环的条件就不满足了,所以退出循环,执行后续语句。你也可以采用下面的方式:
bRun = True
While ....
If Not bRun Then
Exit Sub
End If
....
DoEvents
Wend
...

郭勇的意见:
《解析 事件,Doevents,闲置循环和控时循环中的难点问题》
Visualbasic6.0 代码
copyright guoyong in cqums(2004-2-26)
关键问题归于doevents 函数
DoEvents函数的功能是:转让控制权,以便让操作系统处理其它的事件。
问:为什么要用doevents?
A.在需要用某一循环处理相当耗时或者很快速的代码时,就需要用到它,以便用户能在起处理过程中能做其他事情,即程序能被控制,而不是无响应状态
B.vb6.0中多线程vb代码极度不稳定,而且无法调试,所以vb中的多线程用的很少(注:是指vb的代码在多线程中运行时不稳定)
C.timer控件可以起到后台运行作用,但其是通过事件控制,一是不稳定,二是速度太慢,如果想用其处理高速又耗系统的代码更本不能达到预期的效果

下面将其某些用法和难点简介如下:

(注: '** 后面的代码表示如果在该处用了这个语句
以下代码中用到了一些api函数,请用vb附带的api浏览器查阅)

一. 基本用法:
1.窗体启动时如果要处理的事务太多或者用sleep函数暂停,造成其很久都不能出现时怎么办?
例如代码:
Private Sub Form_Load()
Show
'**DoEvents
Sleep 5000
End Sub
通常容易想到在sleep前加个show,但还是不能达到预想的效果,窗体虽然出来了,但好象只达到了一半,如果加上第3句,将看到效果大不相同

2.如果有个很耗时的循环导致程序不响应,怎么办?
例如:
Dim L As Long
For L = 1 To 1000000
'** DoEvents
Next L
如果无'**,在循环过程中程序无法处理事件,对于用户来说是不响应,无法控制的
3.想在循环中看到处理过程?
同样:
Dim L As Long
For L = 1 To 10000
'** DoEvents
Text1.Text=Cstr(l)
Next L
无'** 时将无法看到text1中的变化,而只在循环结束时看到最后结果
4.怎样中止循环?
如果有:
Private Sub Command3_Click()
Dim L As Long
Do
L = L + 1
Debug.Print L
DoEvents
Loop
End Sub
会发现当关闭窗口后,debug中的数据仍然在变化,说明并没结束
需要如下:
Dim IsExit As Boolean
Private Sub Command1_Click()
Dim L As Long
IsExit = False
Do While DoEvents
If IsExit = True Then Exit Do
L = L + 1
Loop

End Sub

Private Sub Command2_Click()''或者在form_unload模块中等等
IsExit = True
End Sub
其中 isexit是全局变量
<>有些人喜欢用end语句来结束程序,小程序固然可以,但当太大,或者调用了某些特殊的api函数后可能导致预想不到的错误,如果装载了许多东西在程序结束时不处理将卸载很慢,而且这种做法也极不符合正规软件的要求...总之end语句毛病很多,此不详谈,建议少使用甚至不使用

二. 其基本用法大概就这些,现在解析其中的一些[难点]

1.为什么还是不能结束?
代码如下:
Dim IsExit As Boolean
Private Sub Command1_Click()
Dim L As Long
IsExit = False
Do
If IsExit = True Then Exit Do '句0
DoEvents '** 句1
Text1.Text = CStr(L) '** 句2
L = L + 1
Loop
End Sub

Private Sub Form_Load()
Static N As Long
N = N + 1
MsgBox N
End Sub

Private Sub Form_Unload(Cancel As Integer)
IsExit = True
End Sub

运行结果:启动时msg显示1,点击command1,text1在变化
此时再点form右上角的小差(关闭窗体),发现vb运行控制上的按扭并没变化,说明程序还在运行.如果编译成程序后运行,按下ctrl+del+alt也可发现它还没结束.
通过读代码,并没发现错误,怎么回事?

关键在于 句2 访问了控件的属性
代码运行路径:当在doevents 时,程序释放控制权,可以接收事件消息,form-unload事件只能从此处产生,假设此时关闭form ,unload事件发生,即doevents后就运行unload代码,得到isexit=t,并且form卸载,代码返回到doevents 之后,运行 句2.注意现在form 已经卸载了,text1从哪里来呢?
于是form重新装载,代码跳到form_load模块运行,所以在关闭窗体后可以看到msg 显示2,此模块运行完后再继续句2后面的代码,当下次循环遇到 句0时退出循环
另:既然退出了循环,怎么还不能结束?
vb程序规定(其实其他的windows语言一样):窗体卸载时并不是立即卸载其模块代码,而只先卸载窗体中的控件和一些属性值,程序中最后一个窗体卸载时才完全卸载.
在这个单窗体程序中,form卸载时因为循环的控制无法卸载代码,失去了卸载代码的机会,导致再也不能卸载(因为没卸载代码,所以运行的 句2 是并不会出错)
另:既然再次运行了form_load代码,怎么看不见窗体?
因为程序启动时窗体的到显示的消息,而只运行此模块并没有(如果在msgbox n语句前加上show,就可以看到它了)
如何解决?
通过以上分析,应该很简单,把句1 和句2调换一下就可以了,关键:
<仔细分析代码是如何运行的,避免在form已经卸载了情况下访问控件>

2.用了doevents速度太慢了怎么办?
doevents的代价是速度变慢,但要程序响应又不得不用
其实doevents语句允许任何应用程序执行相关事件,而不仅仅是你自己的程序,所以变得很慢.
可以让它响应本程序事件动作,需要用到api函数GetInputState
例如用: If GetInputState() Then DoEvents '来代替doevents可使循环运行更快

3.既要同时响应事件又要控件不变化,怎么办?
例如在一个长的循环中向listview控件中添加记录,无doevents时程序无响应,但有它时控件又闪的厉害
解决办法:a.不一定每次循环都doevents,可以在适当时间时才用,至少没那么闪
b.应用api函数 ValidateRect 功能是使指定的矩型区域生效,通知Windows不对指定的区域进行重画另:InvalidateRect 功能相反,同时需要用到函数 GetClientRect 取得指定对象的矩形区域应用*rect函数指定listview的矩形区不重画,即可避免闪烁(但还是要注意恢复重画,否则看不见了真实效果)

4.控时循环和变速齿轮
请看下面的代码:
Option Explicit
Private Declare Function timeGetTime Lib "winmm.dll" () As Long
Dim IsExit As Boolean
Private Sub Command1_Click()
Dim L As Long
Dim Kt As Long
IsExit = False
Do
Kt = timeGetTime()
'do something
L = L + 1
Text1.Text = L
'DoEvents '句 1
While timeGetTime - Kt < 50 '句 2
'While Abs(timeGetTime - Kt) < 50 '句 3
'While Abs(timeGetTime - Kt) And (Not IsExit) < 50 '句 4

DoEvents '句 5
Wend
'DoEvents '句 6
If IsExit Then Exit Do
Loop
End Sub

Private Sub Form_Unload(Cancel As Integer)
IsExit = True
End Sub
其中可用的代码(除去加"'" 号的代码)就是通常的控时循环代码
运行代码并不会出现错误,但在循环过程,请开启变速齿轮看看
当关闭齿轮时,将发现text1.text停止了,别慌,等一段时间它又会继续(这要看你设定的时间,这里是50毫秒,如果设定的太长text1.text将半天都没变化,这是怎么回事?
变速齿轮在启动时将hook.dll映射到你的程序地址运行,更改了timegettime()函数获取的时间
如果在句2和句3间插入debug.print timegettime,timegettime-kt 将发现,在关闭齿轮的瞬间后者变成了负值,timegettime变小了,所以才造成需要等很久
如果是编写游戏,而用户开了齿轮,那可就惨了

解决方案:
a.用句3代替句2,这个方法最简便,虽然不符实,但不会出问题,建议使用
b.不要句5,换用句6(这样就能达到效果吗?) 因为齿轮还是从doevents语句运行时才能插的进来,所以只要kt=timegettime 和 timegettime之间没有doevents就不会出错
ab.两种方法都有些小问题,但无大碍,有兴趣者请自己分析

5.程序怎么"死了"?
这只是一些人编写时没注意到的小问题,提醒一下:
同样用上面的代码,如果设定的时间太短,以至在代码运行到句2时已经超时了,句5将不能运行了,当然程序就死了哦,以防万一,加上句1,所以此时也只能用a方案来解决齿轮的问题了
有必要用句4代替句3 吗? 除非你设定的时间太长,人家想关闭你的程序要等上好半天

好了,也差不多,该收工了,如果有什么忘了说,你又想知道的话,可以来和我一起探讨
若有什么错了的请指正,谢谢!
希望你能把程序写的更好!

copyright guoyong in cqums(2004-2-26)

是什么呢?

 

查看更多关于【VisualBasic】的文章

展开全文
相关推荐
反对 0
举报 0
评论 0
图文资讯
热门推荐
优选好物
更多热点专题
更多推荐文章
Windows API Reference for C#, VB.NET
不错的.net 下用API的参考站点地址在:http://www.webtropy.com/articles/Win32-API-DllImport-art9.asp 下面摘抄分类,便于大家直接就拿来用: File, Memory, Process, Threading, Time, Console, and Comm control(kernel32.dll) _hread_hwrite_lclose_lcr

0评论2023-03-16877

一个基于API的VB.net串口通讯类 vbnet串口通信如何编写
VB.net的串口通讯支持总是让人觉得有所不足,在使用VB6的MsComm32.ocx时,很多人都会在VB.net的开发中觉得很困扰。    这里讲述的VB.net串口通讯类使用native代码,并且它是通API调用实现的,你会发现VB.net的串口通讯就是这么简单。    在说明如何使

0评论2023-02-12420

[VB][ASP.NET]FileUpload控件「批次上传 / 多档案同时上传」的范例
FileUpload控件「批次上传 / 多档案同时上传」的范例 (VB语法) http://www.dotblogs.com.tw/mis2000lab/archive/2008/05/14/3986.aspx    FileUpload控件真的简单好用,不使用它来作批次上传,却要改用别的方法,实在不聪明。要用就一次用到底,公开File

0评论2023-02-10976

第八章 VB中ActiveX控件的使用
轉自:http://wwww.hyit.edu.cn/edu/vb/study/index.htm第八章          VB中ActiveX控件的使用8.1  概述     这里的ActiveX控件是指VB标准工具箱里没有的控件,用时需从“工程”菜单里选择“部件…”(或右键单击工具箱,从快捷菜单中选择“部

0评论2023-02-10615

第二章 VB的界面设计
轉自:http://wwww.hyit.edu.cn/edu/vb/study/index.htm第二章         VB的界面设计2.1  VB用户界面设计基础1. 概述   界面的设计有两步:先绘制控件,然后确定控件属性。   绘制控件:在工具箱里单击想画的控件,在窗体里按下鼠标并拖曳,然后

0评论2023-02-10497

VB6多线程,关键段操作 vb6.0 多线程
Option Explicit Declare Function GetLastError Lib "kernel32" () As Long 'Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long 'Declare Sub ExitThread Lib "kernel32" (Optional ByVal dwExitCode

0评论2023-02-09486

VB.NET调用IE,并且等待
            Dim p As New Process            '获得URL            aURL = GetURL()            '获得IE路径            p.StartInfo.FileName = System.Environment.GetFolderPath( _ 

0评论2023-02-09939

vb的VSFlexGrid控件 vb msflexgrid
多行选中VSFlexGrid的SelectionMode = flexSelectionListBox,现在可以配合Ctrl进行多行选择循环取值用vsflexgrid.SelectedRows 可以得到你选择的行的总数量然后用循环可以得到具体的行中具体列的内容Dim Temp  As StringDim i As IntegerFor i =

0评论2023-02-09868

转载-公历转换农历VB示例 公历转农历函数
Option ExplicitPrivate LunarInfo(1 To 150) As Double '从1900-2049年这150年的农历信息码Private SolarMonth(1 To 12) As Integer '阳历12个月的天数Private Gan(1 To 10) As String '农历的天干Private Zhi(1 To 12) As String '农历的地支Private Animal

0评论2023-02-09982

[转] VB的Ping 模块
图:Ping通的情况图:Ping失败的情况下面是源代码(VB6):(完善的出错控制,所以是个好函数)Option ExplicitPrivate Const IP_SUCCESS As Long = 0Private Const IP_STATUS_BASE As Long = 11000Private Const IP_BUF_TOO_SMALL As Long = (11000 + 1)Private

0评论2023-02-09407

VB.NET withevent 自定义事件处理
Module Module1    Private WithEvents aemp As part2    Sub Main()        Dim chen As New part2("chen lili", 20000)        aemp = chen        Console.WriteLine(chen.Name" prevouis salary is "chen.Salary)      

0评论2023-02-09571

VB6操作ACCESS文件 vb+access
VB6操作ACCESS文件Option ExplicitConst Dict_DB = "adatabase.mdb"'先要引用Microsoft ActiveX Data Objects 2.8 LibraryPublic cnn As ADODB.ConnectionPublic rst As ADODB.Recordset, rst2 As ADODB.RecordsetPublic cmd As ADODB.CommandPrivate Sub For

0评论2023-02-09762

VB用API实现各种对话框(总结) vbs简单代码对话框
VB用API实现各种对话框(总结)  各种对话框(总结)标准对话框(SmDialog)Option Explicit''定义一个全局变量,用于保存字体的各种属性Public Type SmFontAttrFontName As String '字体名FontSize As Integer '字体大小FontBod As Boolean '是否黑体FontItalic A

0评论2023-02-09401

VB中的正则表达式 vb 正则表达式
RegExp对象提供简单的正则表达式支持功能。  RegExp对象的用法:Function RegExpTest(patrn, strng)Dim regEx, Match, Matches ' 建立变量。Set regEx = New RegExp ' 建立正则表达式。regEx.Pattern = patrn ' 设置模式。regEx.IgnoreCase = True ' 设置是

0评论2023-02-09890

VB 调用水晶报表2
Set rptApp = New CRPEAuto.ApplicationrptApp.LogOnServer "PDSODBC.DLL", "sbd", "sbd", "epm", "epmis"Set rpt = rptApp.OpenReport(App.Path"\\计划管理\\月度保养计划.rpt")rpt.SQLQueryString = strSQL \'strS

0评论2023-02-09631

【VB】StrConv函数 vbUnicode用法
【VB】StrConv函数StrConv(string, conversion, LCID)vbUnicode64根据系统的缺省码页将字符串转成Unicode。vbFromUnicode128将字符串由 Unicode 转成系统的缺省码页。    Windows系统对字符采用了DBCS编码,它是一套单字节和双字节的混合编码,即西文与AS

0评论2023-02-09999

更多推荐