top
Loading...
在VB程序中處理隨機事件
p>在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過程也不一定要全部刪掉,只要將實時查看改為寫入日志文件,作為日后軟件維護的資料。

作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗