|
在Visual
Basic(以下简称VB)程序设计过程中,如何轻松地处理众多的随机事件,往往是制作大型系统首先要考虑的问题之一。例如,多个窗口同时打开同一个表(Table),一个窗口中对数据进行了修改,而其它窗口也能够随之进行数据更新,这时就需要有一条说明数据改变了的消息在所有窗口间进行广播。在C中,只需要定义一条用户消息即可实现这一点;而用VB编程就不那么简单。
早期实现方法及局限性
对于以上问题,笔者早期的实现方法是,自定义一个消息结构(VbMsg),并在程序的主窗体内建立一个消息广播引擎,主要由一个消息队列和一个定时消息广播器所组成。消息广播器每隔一固定时间检查一次消息队列,如果有消息存在,就将其发送给所有打开的窗口,并将该消息从队列中删除。如此再定义一个全局的消息发送过程(SendMsg),将要发送的消息(VbMsg)送入消息队列。这样当需要广播消息时,只需填充好消息结构,调用SendMsg过程即可。
这里较为复杂的是消息广播器如何将消息发送到各窗口。这需要作个硬性规定,即每一个窗体都必须定义一个形式完全相同的消息接收函数(RecMsg),在这个函数中对接收到的消息进行处理,当然也可以什么都不做。有了这样的规定之后,消息广播器在进行广播时,就可以利用VB系统定义的全局变量Forms,遍历所有的窗体,并调用一遍每个窗体的消息接收函数。其主要代码如下:
Public Sub SendMsgToForms(msg as VbMsg) Dim frm as Form
For Each frm In Forms frm.RecMsg msg Next frm End Sub
通过上面的这些过程,就可以实现在独立的程序中,对随机事件进行异步处理。这一方法的效果基本令人满意。但是它有几个较大的局限性:
? 定时检查消息队列需要利用Timer控件进行触发,这在程序运行时,就必然要牺牲一部分效率;
? 消息广播的范围限定在一个程序模块内,如果整个系统分成多个大的模块,那么存在于动态链接模块(.DLL)中的窗体将不能直接接收到广播消息,更无法实现进程间的消息传递;
? 消息的接收者只能是窗体,而作为真正的基础单元“类”却无法直接接收消息。
VB5.0的新特性及实现方法
VB 5.0 企业版增添了 嗲坑辛Φ奶匦裕梢越饩鲆陨夏烟狻!?
1、 用户自定义事件
在类模块中,可以使用Event关键字来定义用户自定义事件,使用 RaiseEvent
语句来产生该事件,这一机制给处理随机事件带来了很大方便。本文中的消息广播引擎,就可以不再使用Timer控件做支持,而是当收到需要广播的消息时,产生一个预定义的事件;而需要处理消息的客体对象,只需截获该事件。
2、 ActiveX EXE组件
利用VB,可以方便地将共享代码封装在ActiveX组件之中,从而可以实现跨进程间的消息传递。因为ActiveX组件有内部(DLL)、外部(EXE)两种,外部组件可以对模块内的全局数据实现共享。
3、 远程自动化连接
ActiveX组件是一种标准的客户机/服务器结构,利用Windows平台的COM模型,VB能够方便地将这种结构扩展到整个网络的范围。所以,消息广播设计既可实现进程间的消息传递,也可实现网络上的消息传递。
根据以上思想,笔者通过四个模块之间的相互协作,完成了消息的发送、广播及接收,并将这四个模块封装在一个ActiveX
EXE组件之中。下面就是这四个类模块的简单介绍及源代码。
类模块之一:Msg.cls
该模块定义了消息数据结构VbMsg类,它是消息传递中的载体。这里只是一个简单的例子,如果想实现更多的功能,如建立两点间的数据通道,而不是单纯的广播消息,则要对该结构进行一些扩充。
BEGIN MultiUse = -1 True END Attribute VB_Name = “VbMsg"
Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False Attribute VB_Exposed = True
Option Explicit 消息类:定义全局的消息结构 Public iType As Long 消息类型编号
Public iName As String 消息名 Public iSource As String 消息源说明 Public
iDescription As String 消息说明 Dim iT As Date 消息发生时间 返回日期型时间
Public Property Get iTime() As Date iTime = iT End Property
返回字符型时间 Public Property Get iTimeStr() As String iTimeStr =
Format(iT, “yyyy.mm.dd hh:mm:ss") End Property 在对象被建立时,设置消息发生时间
Private Sub Class_Initialize() iT = Now() End Sub
类模块之二:MsgCli.cls
本模块是对客户接收端MsgClient类的定义,这相当于一个消息接收器。在这个类中定义的一个RecMsg事件,当接收器收到消息时(过程SetMsg被调用),就产生这一事件;接收器的建立者截获这一事件,并处理消息。为了避免接收不必要的消息,声明了minMsg、maxMsg两个变量,以便对VbMsg中的iType属性进行过滤。
BEGIN MultiUse = -1 True END Attribute VB_Name =
“MsgClient Attribute VB_GlobalNameSpace = False Attribute
VB_Creatable = True Attribute VB_PredeclaredId = False Attribute
VB_Exposed = True Option Explicit 客户消息接收类
定义接收消息事件,该对象的宿主类应截获该事件,并处 理接收到的消息 Public Event RecMsg(ByVal msg
As VbMsg) 通过设置消息的接收范围,过滤掉不需要的消息 Public minMsg As Long Public
maxMsg As Long 该对象的标志编号,使用时不应修改该值 Public ID As Long
事件产生过程,只应由消息服务器(MsgServer)调用 Public Sub SetMsg(msg As VbMsg) If
msg.iType >= minMsg And msg.iType <= maxMsg Then RaiseEvent RecMsg(msg)
nd If nd Sub 根据ID返回对象的关键字,只应由消息服务器调用 Public Property Get
Key() As String Key = “ID:& ID End Property
类模块之三:Global.bas
本模块声明了两个全局变量,一个是接收器(MsgClient)列表(Clients),一个是接收器计数器,为每个接收器分配一个唯一的ID标志。把变量放在单独的模块中,是为了实现数据在进程间的共享,是跨进程间消息传递的关键所在(应保证在编译时工程是单线程的,否则不能实现数据共享)。
Attribute VB_Name = “modGlobal Option Explicit 消息服务器全局变量,消息接收客户列表
Public Clients As New Collection 消息接收客户ID计数器 Public CliCount As
Long
类模块之四:MsgSrv.cls
本模块定义了消息服务器类MsgServer,该类是消息广播引擎的主体,它主要管理维护消息接收器列表(Clients),将发送来的消息(调用SendMsg过程)依次发送给列表中的所有接收器。请注意:为了方便使用,该类被声明为公共全局类。
BEGIN MultiUse = -1 True END Attribute VB_Name =
“MsgServer Attribute VB_GlobalNameSpace = True Attribute VB_Creatable
= True Attribute VB_PredeclaredId = False Attribute VB_Exposed =
True Option Explicit 消息服务器类,发送消息 Public Sub SendMsg(msg As
VbMsg) Dim c As MsgClient For Each c In Clients c.SetMsg msg
DoEvents
Next c End Sub 增删消息接收客户 Public Sub
AddMsgClient(c As MsgClient) CliCount = CliCount + 1 c.Id = CliCount
Clients.Add c, c.Key End Sub Public Sub DelMsgClient(c As
MsgClient) Clients.Remove c.Key If Clients.Count = 0 Then CliCount =
0 End Sub
应用举例
至此,一个小巧灵活的消息广播引擎就完成了,它的使用范围很广,用起来也很方便,只需在工程中引入编译过的ActiveX组件,就可以直接调用SendMsg发送消息。但可能在安装消息接收器(MsgClient)时会稍许有点麻烦,下面举例说明其应用。
在设计Windows程序时,往往希望调试时能看到程序运行时后台的一些情况。利用VB的单步执行或Debug命令,会受到一些限制。利用消息广播引擎,制作一个通用的实时消息事件查看程序,就可以很好地解决这一问题。查看程序的主要工作是捕捉一组事先定义好的消息事件,并将消息的内容显示在列表框内。本应用可以只用一个窗体完成,主要代码如下。
Const MsgInfoID=101 Private WithEvents mClient As MsgClient
Private Sub Form_Load() Set mClient = New MsgClient
MClient.minMsg= MsgInfoID MClient.maxMsg= MsgInfoID AddMsgClient
mClient End Sub Private Sub Form_Unload(Cancel As Integer)
DelMsgClient mClient End Sub Private Sub mClient _RecMsg(ByVal
msg As VbMsgSrv.VbMsg) List1.AddItem msg.iTimeStr & Chr(9) & msg.iName &
Chr(9) & sg.iDescription End Sub
在被调试的程序中,为了调用方便,可以编写一个全局过程:
Const MsgInfoID=101 Public Sub MsgInfo(iName As String,iDes As String)
Dim msg As New MsgClient With msg .iName = iName .
iDescription = iDes End With SendMsg msg End Sub
在程序的重点环节插入MsgInfo过程,运行时有关信息就会在事件查看程序的窗口中显示出来。这种方法尤其适合调试多程序协作的软件系统。当软件系统正式交给用户时,插入的MsgInfo过程也不一定要全部删掉,只要将实时查看改为写入日志文件,作为日后软件维护的资料。
155
[VB.NET程序]GSM短信模块库函数,可以用VB,VC,调用简单实用 [办公软件]PowerPoint做交互课件之弃用VBA [办公软件]VBA获取U盘、主板、CPU序列号和网卡MAC地址 [办公软件]VBA设置文件属性及加密源代码示例 [办公软件]VBA中初始化ADO连接的几种方法 [网络安全]“VB破坏者变种N”病毒摘要 [Web开发]ASP.NET上传文件到数据库VB版 [办公软件]在Excel中利用VBA实现多表单元格数据的读取与赋值… [办公软件]使用Vba读取已关闭的Excel工作薄数据到当前工作表… [办公软件]Excel编程基础之VBA文件操作详解
|