📄 m48.htm
字号:
<html>
<head>
<title>VB教程</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<p align="center"><script src="../../1.js"></script></a>
<body bgcolor="#ffffff" leftmargin="5" topmargin="1" marginheight="5" marginwidth="5">
<div align=center>
<table border=0 cellpadding=0 cellspacing=0 width=680 align="center">
<tbody>
<tr>
<td bgcolor=#000000 height=9>
<div align=center class=H1> <font color="#FFFFFF">VB程序中处理随机事件</font> </font> </font></div>
</td>
</tr>
<tr valign=top>
<td class=H1 height=76>
<p align="left"> <br>
</font></p>
<font color="#000000">在程序设计过程中,如何轻松地处理众多的随机 事件,往往是制作大型系统首先要考虑的问题之一。用C语言开发Windows程序时,可以方便
地使用消息机制(Message),但是,设计VB程序时,就没有这样的方便条件了。例如,多个窗 口同时打开同一个表(Table),当在一个窗口中对数据进行了修改,而其他的窗口也能够随
之进行数据更新,这时就需要有一条说明数据改变了的消息在所有的窗口间进行广播。如 果使用的语言是C,只需要定义一条用户消息(UserMessage),就可以实现这一点。可是如
果是用VB编程,做起来就不是那么简单了,最初我是试着这样实现的: 自定义了一个消息结构(VbMsg),并在程序的主窗 体内,建立一个消息广播引擎,主要由一个消息队列和一个定时消息广播器所组成。消息广
播器固定隔一定时间检查一次消息队列,如果有消息存在,就将其发送给所有的打开的窗 口,并将该消息从队列中删除。如此再定义一个全局的消息发送过程(SendMsg),将要发送
的消息(VbMsg)送入消息队列。这样当需要广播消息时,只需填充好消息结构,调用SendMsg 过程即可。这里较为复杂的是消息广播器如何将消息发送到各窗口:这需要作个硬性规定,
就是每一个窗体都必须定义一个形式完全相同的消息接收函数(RecMsg),在这个函数中对 接收到的消息进行处理,当然也可以什么都不做。有了这样的规定之后,消息广播器在进行
广播时,就可以是利用VB系统定义的全局变量Forms,遍历所有的窗体,并调用一遍每个窗 体的消息接收函数,其样子大致如下: <br>
Public Sub SendMsgToForms(msg as VbMsg)<br>
<br>
Dim frm as Form<br>
<br>
For Each frm In Forms<br>
<br>
frm.RecMsg msg<br>
<br>
Next frm<br>
<br>
End Sub<br>
<br>
通过上面的这些过程,就可以实现在独立的程序中, 对随机事件进行异步处理。这一方法我曾经在早期开发的几个系统中使用,效果基本还是令 人满意的。但是它有几个较大的局限性,当开发更大一些的系统时,就显得不能够满足需要。
主要有以下几点: </font></span>
<ol>
<li> 定时检查消息队列,需要利用Timer控件进行触发。这在程序运行时,就必然要牺牲一
部分效率;<br>
</span></font>
<li> <span class="unnamed1">消息广播的范围限定在一个程序模块内,如果整个系统分成多个大的模块,那么存在
于动态连接模块(.DLL)中的窗体,将不能直接接收到广播消息。而要想实现进程间的消 息传递,这一方法就更加不可能;<br>
</span></font>
<li> <span class="unnamed1">消息的接收者只能是窗体,而做为真正的基础单元--“类”却无法直接接收消息。
</span></font></li>
</ol>
为了打破上面的几点局限性,就必须寻找新的解决办
法。非常庆幸的是,VB5.0企业版的推出,给VB增添了许多强有力的特性,有几点特性,正好 可以帮助我们解决难题。先让我介绍一下这几个特性:
</span> </font>
<ol>
<li> <span class="unnamed1">用户自定义事件:在类模块中,可以使用Event关键字来定义用户自定义事件,使用RaiseEvent
语句来产生该事件,这一机制给处理随机事件带来极大的方便。上面说的消息广播引擎, 就可以不再使用Timer控件做支持,而是当收到需要广播的消息时,产生一个预定义的事
件,而需要处理消息的客体对象,只需截获该事件,就完成了消息的传递。<br>
</span></font>
<li> <span class="unnamed1">ActiveXEXE部件:利用VB,可以方便地将共享代码封装在ActiveX部件之中。将消息
广播引擎实现于一个ActiveX部件之中,不仅方便了在程序中使用,而且更为重要的一点 是,可以实现跨进程间的消息传递。因为ActiveX部件有内部(DLL)外部(EXE)两种,对于
外部部件,可以对模块内的全局数据实现共享(关于ActiveX两种代码部件的区别,请阅 读VB的联机帮助文件)。<br>
</span></font>
<li> <span class="unnamed1">远程自动化连接:ActiveX部件,是一种标准的客户机/服务器结构,利用Windows平台
的COM模型,VB已能方便地将这种结构扩展到整个网络的范围。所以,我们的消息广播设 计,在实现了进程间的消息传递之后,进而实现网络上的消息传递,也成为可能。
</span></font></li>
</ol>
通过上面的几点介绍,这一方式的设计思想也就比较
清楚了,在具体设计时,我通过四个模块之间的相互协作,完成了消息的发送、广播及接收,并 将这四个模块封装在一个ActiveXEXE部件之中。下面就是这三个类模块的简单介绍及源代
码: 类模块之一:Msg.cls 在该模块中,定义了消息数据结构VbMsg类,它是消息 传递中的载体。这里只是一个简单的例子,如果想实现更多的功能,如建立两点间的数据通道,
而不是单纯的广播消息,则可能需要对该结构进行一些扩充。 <br>
VERSION 1.0 CLASS<br>
<br>
BEGIN<br>
<br>
MultiUse = -1 'True<br>
<br>
END<br>
<br>
Attribute VB_Name = "VbMsg"<br>
<br>
Attribute VB_GlobalNameSpace = False<br>
<br>
Attribute VB_Creatable = True<br>
<br>
Attribute VB_PredeclaredId = False<br>
<br>
Attribute VB_Exposed = True<br>
<br>
Option Explicit<br>
<br>
<br>
<br>
' ---<br>
<br>
' 说 明:<br>
<br>
'<br>
<br>
' 消 息 类: 定 义 全 局 的 消 息 结 构<br>
<br>
' ---<br>
<br>
<br>
<br>
Public iType As Long ' 消 息 类 型 编 号<br>
<br>
Public iName As String ' 消 息 名<br>
<br>
Public iSource As String ' 消 息 源 说 明<br>
<br>
Public iDescription As String ' 消 息 说 明<br>
<br>
<br>
<br>
Dim iT As Date ' 消 息 发 生 时 间<br>
<br>
<br>
<br>
' 返 回 日 期 型 时 间<br>
<br>
Public Property Get iTime() As Date<br>
<br>
iTime = iT<br>
<br>
End Property<br>
<br>
<br>
<br>
' 返 回 字 符 型 时 间<br>
<br>
Public Property Get iTimeStr() As String<br>
<br>
iTimeStr = Format(iT, "yyyy.mm.dd hh:mm:ss")<br>
<br>
End Property<br>
<br>
<br>
<br>
' 在 对 象 被 建 立 时, 设 置 消 息 发 生 时 间<br>
<br>
Private Sub Class_Initialize()<br>
<br>
iT = Now()<br>
<br>
End Sub<br>
<br>
类模块之二:MsgCli.cls 本模块是对客户接收端MsgClient类的定义,这相当 于一个消息接收器。在这个类中定义的一个RecMsg事件,当接收器收到消息时(过程SetMsg被
调用),就产生这一事件。接收器的建立者就截获这一事件,并处理消息。为了避免接收不必要 的消息,声明了minMsg、maxMsg两个变量,以便对VbMsg中的iType属性进行过滤。
<br>
VERSION 1.0 CLASS<br>
<br>
BEGIN<br>
<br>
MultiUse = -1 'True<br>
<br>
END<br>
<br>
Attribute VB_Name = "MsgClient"<br>
<br>
Attribute VB_GlobalNameSpace = False<br>
<br>
Attribute VB_Creatable = True<br>
<br>
Attribute VB_PredeclaredId = False<br>
<br>
Attribute VB_Exposed = True<br>
<br>
Option Explicit<br>
<br>
<br>
<br>
' ---<br>
<br>
' 说 明:<br>
<br>
'<br>
<br>
' 客 户 消 息 接 收 类<br>
<br>
' ---<br>
<br>
'<br>
<br>
' 定 义 接 收 消 息 事 件, 该 对 象 的 宿 主 类 应 截 获 该 事 件, 并 处 理<br>
<br>
' 接 收 到 的 消 息。<br>
<br>
Public Event RecMsg(ByVal msg As VbMsg)<br>
<br>
'<br>
<br>
' 通 过 设 置 消 息 的 接 收 范 围, 可 以 过 滤 掉 不 需 要 的 消 息<br>
<br>
Public minMsg As Long<br>
<br>
Public maxMsg As Long<br>
<br>
'<br>
<br>
' 该 对 象 的 标 志 编 号, 使 用 时 不 应 修 改 该 值<br>
<br>
Public ID As Long<br>
<br>
'<br>
<br>
' 事 件 产 生 过 程, 只 应 由 消 息 服 务 器(MsgServer) 调 用<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -