欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

標題: 創建向導樣式的數據輸入窗體 [打印本頁]

作者: 51黑科技    時間: 2016-2-3 23:21
標題: 創建向導樣式的數據輸入窗體
引言:本文來源于《Pro Excel VBA》的第4章的示例,主要為學習VBA用戶窗體提供參考。本文“超長”,但如果能夠仔細研讀,一定會有很豐富的收獲。

可以先下載示例文檔:

向導樣式的輸入是相當普遍的技術,用于幫助用戶輸入較多的或復雜的數據。向導允許將數據分成相互聯系的部分,通過按順序輸入數據的過程指導用戶。
示例工作簿名稱為HRWizard.xlsm,由2個工作表組成,名為EmpData的工作表為員工數據庫工作表,名為ListMgr的工作表包含在創建數據輸入窗體向導時使用的不同的列表。(其實還有一個名為UFormConfig的工作表,存放著向導步驟的信息)

EmpData工作表被分成4部分:Personal、Address、Equipment、Access,如下列圖所示。

員工個人信息

員工地址信息

員工設備信息

員工訪問信息
下面的向導窗體將引導用戶為新員工輸入信息。
布局向導窗體
1、打開VBE,添加新用戶窗體。
2、將用戶窗體的高度設置為320,寬度為332。
3、將用戶窗體重命名為HRWizard。
4、在用戶窗體頂部添加標簽,將其Caption屬性設置為:MyCompany – HRWizard,設置字體為大尺寸,如18pt。
5、在用戶窗體中添加一個多頁控件。
6、設置該控件的Height屬性為216,Width屬性為270。
7、將其在用戶窗體中居中,在用戶窗體底部留出空間。
此時的用戶窗體如下圖所示。

由于有4個數據集合部分,需要再添加兩個頁。
1、在多頁控件頂部的選項卡中單擊右鍵。
2、在快捷菜單中選擇“新建頁”,如下圖所示。

3、重復上面的步驟。
此時的用戶窗體如下圖所示。

在用戶窗體中添加控件
在“Page1”中添加的控件如下表所示,與EmpData工作表中個人信息列標題一致。
表:HRWizard用戶窗體控件

在多頁控件的下方添加四個命令按鈕。

現在的用戶窗體和下圖相似。

在“Page2”中添加的控件如下表所示,與EmpData工作表中地址信息列標題一致。
表:Address選項卡控件設置

Page2如下圖所示。

在“Page3”中添加的控件如下表所示,與EmpData工作表中設備信息列標題一致。
表:設備選項卡控件設置

Page3如下圖所示。

在“Page4”中添加的控件如下表所示,與EmpData工作表中訪問信息列標題一致。
表:訪問選項卡控件設置

Page4如下圖所示。

至此,界面設計完成。
接下來,設置一些類來使用戶窗體工作。一開始,可能認為一個與數據記錄相聯系的類就滿足要求了,但我們將在定義類時分解功能區,設計一兩個類幫助定義向導步驟。最終,將有一個靈活的向導應用程序,提供非常容易修改步驟的順序的能力,甚至添加一個步驟也相當簡單。
HRWizard類
由于正收集的某些員工信息將被傳遞給其它部門去處理,因此在自已的類中放置從每個屏幕中獲得的數據。也需要一個監控向導步驟的類,同時考慮一個幫助使用ListMgr工作表中數據填充列表的類。下表列出了每個類并描述了其功能。
表:HRWizard應用程序類模塊


HRWizard商業對象
下面開始設計商業對象。這些類存儲每個對象的數據,包含每個對象的一些商業規則。
在工程中添加一個新的類模塊并將其命名為cPerson,再添加另外三個類模塊,分別將它們命名為cAddress、cEquipment和cAccess。cPerson對象包含一個cAddress對象、cEquipment對象、一個cAccess對象。要保持它們同步,對這四個商業對象類的每一個都添加一個ID屬性。
在每個類中,添加下列模塊級的聲明:

描述
cPerson包含新記錄中的所有個人信息
cAddress包含新記錄中的所有地址信息
cEquipment包含新記錄中的所有設備信息
cAccess包含新記錄中的所有訪問信息
cStep包含向導每一步的配置值
cStepMgr 控制向導的操作及管理cStep對象的集合
cListMgr控制用戶窗體中填充組合框的列表
cHRData從商業對象中將數據轉移到數據庫;將數據從數據庫發送到商業對象
Private m_lngID As Long Public Property Get ID() As Long ID = m_lngIDEnd Property Public Property Let ID(newID As Long) m_lngID = newIDEnd Property

現在,讓我們集中開發cPerson類。每個類實質上對應著先前我們設計的每一個界面。
在cPerson類中添加下列模塊級變量聲明:

Private m_sFName As StringPrivate m_sMidInit As StringPrivate m_sLName As StringPrivate m_dtDOB As DatePrivate m_sSSN As StringPrivate m_sJobTitle As StringPrivate m_sDepartment As StringPrivate m_sEmail As StringPrivate m_oAddress As cAddressPrivate m_oEquipment As cEquipmentPrivate m_oAccess As cAccess

注意,除了從屏幕設計中的數據輸入項外,還包括包含地址、設備和訪問信息的對象。
這里首先要做的是初始化cPerson類,設置一些默認值。在Class_Initialize事件中,添加下列代碼:

Private Sub Class_Initialize() m_lngID = RandomNumber(100000, 999999) Set m_oAddress = New cAddress Set m_oEquipment = New cEquipment Set m_oAccess = New cAccess SetObjectIDsEnd Sub

上述代碼中,設置了私有的ID變量m_lngID為隨機的6位數字,并初始化私有的商業對象變量。然后調用私有的函數SetObjectIDs設置所有四個商業對象的ID值為相同的值。添加下列代碼到cPerson類中生成隨機數字和同步ID字段:

Private Function RandomNumber(upper As Long, lower As Long) As Long '生成一個介于upper和lower之間的隨機數 Randomize RandomNumber = Int((upper - lower + 1) * Rnd + lower)End Function Private Sub SetObjectIDs() m_oAddress.ID = m_lngID m_oEquipment.ID = m_lngID m_oAccess.ID = m_lngIDEnd Sub

在ID Property Let函數中添加對上面的過程的調用。這樣,如果手工對ID字段賦值,那么所有的商業對象都獲取這個新值。最終的ID Property Let過程代碼如下:

Public Property Let ID(newID As Long) m_lngID = newID SetObjectIDs '保持所有對象同步使用相同的IDEnd Property

cPerson類的剩余部分非常直觀。最終的cPerson類的代碼如下:

Property Get FName() As String FName = m_sFNameEnd Property Property Let FName(newFName As String) m_sFName = newFNameEnd Property Property Get MidInit() As String MidInit = m_sMidInitEnd Property Property Let MidInit(newMidInit As String) m_sMidInit = newMidInitEnd Property Property Get LName() As String LName = m_sLNameEnd Property Property Let LName(newLName As String) m_sLName = newLNameEnd Property Property Get DOB() As Date DOB = m_dtDOBEnd Property Property Let DOB(newDOB As Date) m_dtDOB = newDOBEnd Property Property Get SSN() As String SSN = m_sSSNEnd Property Property Let SSN(newSSN As String) m_sSSN = newSSNEnd Property Property Get JobTitle() As String JobTitle = m_sJobTitleEnd Property Property Let JobTitle(newJobTitle As String) m_sJobTitle = newJobTitleEnd Property Property Get Department() As String Department = m_sDepartmentEnd Property Property Let Department(newDepartment As String) m_sDepartment = newDepartmentEnd Property Property Get Email() As String Email = m_sEmailEnd Property Property Let Email(newEmail As String) m_sEmail = newEmailEnd Property Property Get Address() As cAddress Set Address = m_oAddressEnd Property Property Set Address(newAddress As cAddress) Set m_oAddress = newAddressEnd Property Property Get Equipment() As cEquipment Set Equipment = m_oEquipmentEnd Property Property Set Equipment(newEquipment As cEquipment) Set m_oEquipment = newEquipmentEnd Property Property Get Access() As cAccess Set Access = m_oAccessEnd Property Property Set Access(newAccess As cAccess) Set m_oAccess = newAccessEnd Property

至此,已經完成Person數據元素的添加,以及3個對象類屬性。同時,想要添加一個屬性,返回員工的全名。下面的代碼在cPerson中添加只讀的FullName屬性:

Property Get FullName() As String Dim sReturn As String Dim blnMidInit As Boolean  blnMidInit = Len(m_sMidInit & "") > 0  If blnMidInit Then sReturn = m_sFName & " " & m_sMidInit & " " & m_sLName Else sReturn = m_sFName & " " & m_sLName End If  FullName = sReturnEnd Property

這就是我們所需要的cPerson類。
下面列出其它3個類的代碼。
cAddress類:

Private m_lngID As LongPrivate m_sStreetAddress As StringPrivate m_sStreetAddress2 As StringPrivate m_sCity As StringPrivate m_sState As StringPrivate m_sZipCode As StringPrivate m_sPhoneNumber As StringPrivate m_sCellPhone As String Public Property Get ID() As Long ID = m_lngIDEnd Property Public Property Let ID(newID As Long) m_lngID = newIDEnd Property Public Property Get StreetAddress() As String StreetAddress = m_sStreetAddressEnd Property Public Property Let StreetAddress(newAddress As String) m_sStreetAddress = newAddressEnd Property Public Property Get StreetAddress2() As String StreetAddress2 = m_sStreetAddress2End Property Public Property Let StreetAddress2(newAddress2 As String) m_sStreetAddress2 = newAddress2End Property Public Property Get City() As String City = m_sCityEnd Property Public Property Let City(newCity As String) m_sCity = newCityEnd Property Public Property Get State() As String State = m_sStateEnd Property Public Property Let State(newState As String) m_sState = newStateEnd Property Public Property Get ZipCode() As String ZipCode = m_sZipCodeEnd Property Public Property Let ZipCode(newZipCode As String) m_sZipCode = newZipCodeEnd Property Public Property Get PhoneNumber() As String PhoneNumber = m_sPhoneNumberEnd Property Public Property Let PhoneNumber(newPhoneNumber As String) m_sPhoneNumber = newPhoneNumberEnd Property Public Property Get CellPhone() As String CellPhone = m_sCellPhoneEnd Property Public Property Let CellPhone(newCellPhone As String) m_sCellPhone = newCellPhoneEnd Property

cEquipment類:

Private m_lngID As LongPrivate m_sPCType As StringPrivate m_sPhoneType As StringPrivate m_sLocation As StringPrivate m_sFaxYN As String Public Property Get ID() As Long ID = m_lngIDEnd Property Public Property Let ID(newID As Long) m_lngID = newIDEnd Property Public Property Get PCType() As String PCType = m_sPCTypeEnd Property Public Property Let PCType(newPCType As String) m_sPCType = newPCTypeEnd Property Public Property Get PhoneType() As String PhoneType = m_sPhoneTypeEnd Property Public Property Let PhoneType(newPhoneType As String) m_sPhoneType = newPhoneTypeEnd Property Public Property Get Location() As String Location = m_sLocationEnd Property Public Property Let Location(newLocation As String) m_sLocation = newLocationEnd Property Public Property Get FaxYN() As String FaxYN = m_sFaxYNEnd Property Public Property Let FaxYN(newFaxYN As String) m_sFaxYN = newFaxYNEnd Property

cAccess類:

Private m_lngID As LongPrivate m_sBuilding As StringPrivate m_iNetworkLevel As IntegerPrivate m_sRemoteYN As StringPrivate m_sParkingSpot As String Public Property Get ID() As Long ID = m_lngIDEnd Property Public Property Let ID(newID As Long) m_lngID = newIDEnd Property Public Property Get Building() As String Building = m_sBuildingEnd Property Public Property Let Building(newBuilding As String) m_sBuilding = newBuildingEnd Property Public Property Get NetworkLevel() As Integer NetworkLevel = m_iNetworkLevelEnd Property Public Property Let NetworkLevel(newNetworkLevel As Integer) m_iNetworkLevel = newNetworkLevelEnd Property Public Property Get RemoteYN() As String RemoteYN = m_sRemoteYNEnd Property Public Property Let RemoteYN(newRemoteYN As String) m_sRemoteYN = newRemoteYNEnd Property Public Property Get ParkingSpot() As String ParkingSpot = m_sParkingSpotEnd Property Public Property Let ParkingSpot(newParkingSpot As String) m_sParkingSpot = newParkingSpotEnd Property

管理列表
在HRWizard用戶窗體中輸入的一些數據是通過組合框控件顯示給用戶的。HRWizard工作簿文件包含一個名為ListMgr的工作表,其中包含每個列表的數據。這些數據存儲在ListMgr工作表的命名區域。
cListManager類包含的函數可以從這些命名區域中填充組合框,同時也有一個將列表綁定到VBA Collection對象的方法。
插入一個新的類模塊,將其命名為cListManager,在其中添加下面兩個方法:

Public Sub BindListToRange(ListRangeName As String, TheCombo As MSForms.ComboBox) TheCombo.RowSource = ListRangeNameEnd Sub Public Sub BindListToCollection(TheCollection As Collection, TheCombo As MSForms.ComboBox) Dim iNumItems As Integer Dim i As Integer iNumItems = TheCollection.Count For i = 1 To iNumItems TheCombo.AddItem TheCollection(i) Next iEnd Sub

BindListToRange方法接受區域名稱字符串值和ComboBox對象,設置組合框的RowSource屬性為命名區域。BindListToCollection方法簡單地遍歷集合并調用組合框的AddItem方法。
數據類
數據類被命名為cHRData,這是一個專門為HRWizard應用程序設計的類。
插入一個新的類模塊,將其命名為cHRData。在其中添加下面的模塊級變量、一個屬性和一個方法。

Private m_oWorksheet As WorksheetPrivate m_lngNewRowNum As LongPrivate m_oEmployee As cPersonPrivate m_oXL As cExcelUtils Public Property Get Worksheet() As Worksheet Set Worksheet = m_oWorksheetEnd Property Public Property Set Worksheet(newWorksheet As Worksheet) Set m_oWorksheet = newWorksheetEnd Property Public Function SaveEmployee(Employee As cPerson) As Boolean Dim blnReturn As Boolean  If m_oWorksheet Is Nothing Then GoTo Exit_Function End If  m_lngNewRowNum = m_oXL.FindEmptyRow(m_oWorksheet) Set m_oEmployee = Employee  SaveEmpData SaveAddressData SaveEquipmentData SaveAccessData Exit_Function: SaveEmployee = blnReturn Exit FunctionEnd Function

添加下列類初始化和清理代碼:

Private Sub Class_Initialize() Set m_oXL = New cExcelUtilsEnd Sub Private Sub Class_Terminate() Set m_oXL = NothingEnd Sub

Worksheet屬性讓我們定義工作簿中存儲數據的地方。當傳遞cPerson對象時SaveEmployee方法為我們做一些事情:

Public Function SaveEmployee(Employee As cPerson) As Boolean

檢查是否設置了Worksheet屬性,以便知道在哪里保存數據:

If m_oWorksheet Is Nothing Then GoTo Exit_Function End If

使用cExcelUtils對象找到第一個空行:

m_lngNewRowNum = m_oXL.FindEmptyRow(m_oWorksheet)

接下來,將傳遞給該方法的cPerson對象賦值給私有的用于不同的保存函數的模塊級cPerson對象:

Set m_oEmployee = Employee

最后,觸發一些保存函數,每個數據對象一個:

SaveEmpData SaveAddressData SaveEquipmentData SaveAccessData

Save方法簡單地將存儲在cPerson對象(及其內部的數據對象)中的數據轉換到EmpData工作表中的單元格。在cHRData類模塊中添加下列Save方法:

Private Sub SaveEmpData() With m_oWorksheet .Cells(m_lngNewRowNum, 1).Value = m_oEmployee.ID .Cells(m_lngNewRowNum, 2).Value = m_oEmployee.FName .Cells(m_lngNewRowNum, 3).Value = m_oEmployee.MidInit .Cells(m_lngNewRowNum, 4).Value = m_oEmployee.LName .Cells(m_lngNewRowNum, 5).Value = m_oEmployee.DOB .Cells(m_lngNewRowNum, 6).Value = m_oEmployee.SSN .Cells(m_lngNewRowNum, 7).Value = m_oEmployee.JobTitle .Cells(m_lngNewRowNum, 8).Value = m_oEmployee.Department .Cells(m_lngNewRowNum, 9).Value = m_oEmployee.Email End WithEnd Sub Private Sub SaveAddressData() With m_oWorksheet .Cells(m_lngNewRowNum, 10).Value = m_oEmployee.Address.StreetAddress .Cells(m_lngNewRowNum, 11).Value = m_oEmployee.Address.StreetAddress2 .Cells(m_lngNewRowNum, 12).Value = m_oEmployee.Address.City .Cells(m_lngNewRowNum, 13).Value = m_oEmployee.Address.State .Cells(m_lngNewRowNum, 14).Value = m_oEmployee.Address.ZipCode .Cells(m_lngNewRowNum, 15).Value = m_oEmployee.Address.PhoneNumber .Cells(m_lngNewRowNum, 16).Value = m_oEmployee.Address.CellPhone End WithEnd Sub Private Sub SaveEquipmentData() With m_oWorksheet .Cells(m_lngNewRowNum, 17).Value = m_oEmployee.Equipment.PCType .Cells(m_lngNewRowNum, 18).Value = m_oEmployee.Equipment.PhoneType .Cells(m_lngNewRowNum, 19).Value = m_oEmployee.Equipment.Location .Cells(m_lngNewRowNum, 20).Value = m_oEmployee.Equipment.FaxYN End WithEnd Sub Private Sub SaveAccessData() With m_oWorksheet .Cells(m_lngNewRowNum, 21).Value = m_oEmployee.Access.Building .Cells(m_lngNewRowNum, 22).Value = m_oEmployee.Access.NetworkLevel .Cells(m_lngNewRowNum, 23).Value = m_oEmployee.Access.RemoteYN .Cells(m_lngNewRowNum, 24).Value = m_oEmployee.Access.ParkingSpot End WithEnd Sub

注意,用于獲取cPerson對象的內部的Address、Equipment、Access對象數據的語法:

m_oEmployee.Address.StreetAddressm_oEmployee.Equipment.PCTypem_oEmployee.Access.Building

在一個對象里使用另一個對象可以靈活地分類對象中的信息。
管理向導
創建兩個類來幫助管理向導應用程序。第一個非常簡單,包含每步的配置數據,接著創建一個類,包含這些“向導步驟”對象的集合,管理向導過程的操作。
插入一個新的類模塊,將其命名為cStep,添加下列代碼:

Private m_iOrder As IntegerPrivate m_iPage As IntegerPrivate m_sCaption As String Public Property Get Order() As Integer Order = m_iOrderEnd Property Public Property Let Order(newOrder As Integer) m_iOrder = newOrderEnd Property Public Property Get Page() As Integer Page = m_iPageEnd Property Public Property Let Page(newPage As Integer) m_iPage = newPageEnd Property Public Property Get Caption() As String Caption = m_sCaptionEnd Property Public Property Let Caption(newCaption As String) m_sCaption = newCaptionEnd Property

HRWizard.xlms工作簿包含一個名為UFormConfig的工作表,該工作表包含向導中每個步驟的信息。在這里,可以修改步驟的順序或者插入一個新步驟。
下表列出了cStep類的屬性及其描述。
表:cStep屬性


下面,設置一個類來管理向導中的步驟。在這個類中,將創建cStep對象的集合,用于追蹤我們在處理過程中的哪一步以及共有多少步。
插入一個新的類模塊,將其命名為cStepManager,添加下列模塊級的變量聲明:

描述
Order包含向導處理的順序里步驟的位置
Page包含與多頁控件中相應的頁面一致的頁號
Caption顯示在當前活動頁控件中的文本
Dim m_oStep As cStepDim m_iNumSettings As IntegerDim m_iNumSteps As IntegerDim m_iCurrentPage As IntegerDim m_iPreviousPage As IntegerDim m_iNextPage As IntegerDim WithEvents m_oPreviousButton As MSForms.CommandButtonDim WithEvents m_oNextButton As MSForms.CommandButtonDim m_oWorksheet As Worksheet

通過接下來的一些Integer變量,cStep對象m_oStep用于填充向導步驟的集合。告訴有多少步驟,每步有多少屬性,基于用戶在向導的位置追蹤當前、下一個、前一個步驟。
接下來,有兩個設置為MSForms.CommandButton對象類型的變量,它們被聲明為WithEvents。我們讓cStepManager類維護這些按鈕的狀態。WithEvents聲明來捕獲它們的Click事件,并在類里面執行操作。使用Click事件基于用戶在向導中的位置決定是否啟用按鈕。
在cStepManager中添加下面的代碼:

Public Property Get NumberOfSettings() As Integer NumberOfSettings = m_iNumSettingsEnd Property Public Property Let NumberOfSettings(newNum As Integer) m_iNumSettings = newNumEnd Property '工作表屬性:獲取/設置包含步驟信息的工作表Public Property Get Worksheet() As Worksheet Set Worksheet = m_oWorksheetEnd Property Public Property Set Worksheet(newWorksheet As Worksheet) Set m_oWorksheet = newWorksheetEnd Property Public Property Get CurrentPage() As Integer CurrentPage = m_iCurrentPageEnd Property Public Property Let CurrentPage(newPage As Integer) m_iCurrentPage = newPageEnd Property Public Property Get PreviousPage() As Integer PreviousPage = m_iCurrentPage - 1End Property Public Property Get NextPage() As Integer NextPage = m_iCurrentPage + 1End Property Public Property Set PreviousButton(newPreviousBtn As MSForms.CommandButton) Set m_oPreviousButton = newPreviousBtnEnd Property Public Property Set NextButton(newNextBtn As MSForms.CommandButton) Set m_oNextButton = newNextBtnEnd Property

下表列出了cStepManager類的屬性及其描述。
表:cStepManager屬性


需要在類中添加更多的屬性。下面的只讀屬性包含cStep對象的集合,包含向導的每一步的信息。
PageSettings屬性存儲該集合,使用HRWizard用戶窗體后臺的客戶端代碼返回一個Collection對象。
PageSettings屬性的代碼如下:

描述
NumberOfSettings包含步驟配置工作表UFormConfig中的列數
Worksheet告訴類到哪里查找向導的每步的信息
CurrentPage在向導中存儲當前步驟的值
PreviousPage基于CurrentPage屬性計算;返回向導中前一步驟的值
NextPage基于CurrentPage屬性計算;返回向導中下一步驟的值
PreviousButton存儲用戶窗體中導航到向導的前一步的按鈕的指針
NextButton存儲用戶窗體中導航到向導的后一步的按鈕的指針
Public Property Get PageSettings() As Collection Dim colReturn As Collection Dim numrows As Integer Dim row As Integer Dim col As Integer Dim sKey As String  Set colReturn = New Collection  numrows = m_oWorksheet.Cells(Rows.Count, 1).End(xlUp).row  For row = 2 To numrows Set m_oStep = New cStep For col = 1 To m_iNumSettings Select Case col Case 1 m_oStep.Order = m_oWorksheet.Cells(row, col).Value sKey = CStr(m_oStep.Order) Case 2 m_oStep.Page = m_oWorksheet.Cells(row, col).Value Case 3 m_oStep.Caption = m_oWorksheet.Cells(row, col).Value End Select Next col colReturn.Add m_oStep, sKey Next row  m_iNumSteps = colReturn.Count Set PageSettings = colReturnEnd Property

我們首先做的是獲取工作表中已使用的區域的行數:

numrows = m_oWorksheet.Cells(Rows.Count, 1).End(xlUp).row

注意,雖然Excel的Worksheet對象有Rows.Count方法,但是在這里不能使用(m_oWorksheet.Rows.Count)。這將返回工作表中的總行數,這樣不僅提供不正確的值,而且也會使Integer變量溢出。
接下來,循環填充cStep對象集合,代碼如下:

For row = 2 To numrows Set m_oStep = New cStep For col = 1 To m_iNumSettings Select Case col Case 1 m_oStep.Order = m_oWorksheet.Cells(row, col).Value sKey = CStr(m_oStep.Order) Case 2 m_oStep.Page = m_oWorksheet.Cells(row, col).Value Case 3 m_oStep.Caption = m_oWorksheet.Cells(row, col).Value End Select Next col colReturn.Add m_oStep, sKey Next row

上述代碼中,首先做的是實例化一個新的cStep對象,然后移到內部循環遍歷配置工作表中的列,將它們賦給內部的cStep對象的相應屬性。這段代碼運行前,已經通過NumberOfSettings屬性設置m_iNumSettings值。
最后,將cStep對象添加到內部的集合colReturn中,在該集合中傳遞Order值作為主鍵。
注意,在外部循環中的第一行代碼,Set m_oStep=New cStep,是重要的。如果忽略該代碼,那么集合中將以四個相同的cStep對象結束(全部都包含從工作表中讀取的最后一個配置項中的數據)。這是因為m_oStep對象引用仍然是當前引用,所以每次調用時都會修改任何已存在的實例。通過使用New關鍵字,創建新的、單獨的對象實例。
最后,設置內部的m_iNumSteps變量,用來追蹤前一個和下一個可用的命令按鈕,并且最終返回集合:

m_iNumSteps = colReturn.Count Set PageSettings = colReturn

現在,將注意力轉向PreviousButton屬性和NextButton屬性。記得這些屬性的內置變量被聲明為WithEvents。當聲明一個對象時使用WithEvents時,可以通過VB代碼窗口的對象框訪問該對象的事件代碼,如下圖所示。

從對象框中選擇m_oNextButton和m_oPreviousButton,在類模塊中插入事件處理代碼塊,并在其中添加代碼如下:

Private Sub m_oNextButton_Click() m_oNextButton.Enabled = Me.NextPage <> m_iNumSteps + 1 m_oPreviousButton.Enabled = Me.PreviousPage <> 0End Sub Private Sub m_oPreviousButton_Click() m_oPreviousButton.Enabled = Me.PreviousPage <> 0 m_oNextButton.Enabled = Me.NextPage <> m_iNumSteps + 1End Sub

這段代碼基于cStepManager類的NextPage或PreviousPage屬性控制每個按鈕是否啟用。當該類首次在客戶端代碼中被創建時,再添加一個方法初始化按鈕:

Public Sub HandleControls() m_oPreviousButton.Enabled = Me.PreviousPage <> 0 m_oNextButton.Enabled = Me.NextPage <> m_iNumSteps + 1End Sub

到現在為止,我們已經創建了相當數量的代碼,全都存儲在跨越許多類模塊的對象中。通過劃分功能,使維護代碼的工作非常容易。如果需要綁定列表到目前還沒有處理的數據源,只需在cListManage類中添加一個新方法。如果需要在數據處理過程中添加一個屏幕界面,則在多頁控件中設計一個新頁面,創建一個新類去存儲屏幕信息,并在配置表中添加一行。
在添加完所有的類模塊并編寫好代碼后,工程資源管理器中的類模塊文件夾應該如下圖所示。

編寫HRWizard用戶窗體代碼
現在,我們已經完成了最艱難的工作。是到將對象放進HRWizard用戶窗體里并使這些對象工作的時候了。
打開HRWizard用戶窗體代碼窗口,添加下列模塊級的變量聲明:

Dim m_oEmployee As cPersonDim m_oLM As cListManagerDim m_oWizard As cStepManagerDim m_colSteps As Collection

雖然我們創建了9個分開的類模塊來運行我們的應用程序,但是許多類都是通過在聲明部分列出來內部使用。使用cPeason類收集新員工的數據,使用cListManager類來填充HRWizard用戶窗體中不同的組合框,使用cStepManager類決定何時且按什么順序顯示哪個屏幕,并控制導航命令按鈕的可用性。最后,使用標準的VBA Collection對象,用于存儲cStepManager對象的PageSettings集合。
初始化應用程序
在HRWizard用戶窗體的Initialize事件中,將初始化自定義的對象并添加代碼來設置向導、列表和顯示用戶窗體。
在UserForm_Initialize事件中添加下列代碼:

Private Sub UserForm_Initialize() Set m_oEmployee = New cPerson Set m_oLM = New cListManager Set m_oWizard = New cStepManager  InitWizard InitLists InitFormEnd Sub

下面,創建三個Init函數,分別設置向導、列表管理器和用戶窗體對象。
初始化向導
在用戶窗體代碼窗口添加新的子程序,將其命名為InitWizard,并添加下列代碼:

Private Sub InitWizard() With m_oWizard Set .Worksheet = Sheets("UFormConfig") .NumberOfSettings = 3 Set m_colSteps = .PageSettings Set .PreviousButton = Me.cmdPrevious Set .NextButton = Me.cmdNext .CurrentPage = MultiPage1.Value + 1 End WithEnd Sub

上述代碼完成下列工作:

因為多頁控件的Page集合基于0,所以使用多頁控件的Value屬性加1來設置CurrentPage屬性。
在初始化用戶窗體之前,必須設置cStepManager對象,因為該用戶窗體使用PageSettings集合來設置它自已。
初始化組合框
下一步是將組合框綁定到它們各自的列表。該列表被存儲在ListMgr工作表中。
插入一個新的子程序,并將其命名為InitLists,添加下列代碼:

Private Sub InitLists() With m_oLM .BindListToRange "Departments", Me.cboDept .BindListToRange "Locations", Me.cboLocation .BindListToRange "NetworkLvl", Me.cboNetworkLvl .BindListToRange "ParkingSpot", Me.cboParkingSpot .BindListToRange "YN", Me.cboRemoteAccess End WithEnd Sub

同樣,上述代碼也非常簡單,它們為應用程序中的每個列表調用cListManager對象的BindListToRange方法。
初始化用戶窗體
在設置應用程序中的最后一步是初始化用戶窗體自身。創建一個名為InitForm的新子程序,并添加下列代碼:

Private Sub InitForm() Dim iFirstPage As Integer Dim i As Integer Dim iPageCount As Integer  iFirstPage = m_colSteps("1").Order - 1 Me.MultiPage1.Value = iFirstPage Me.MultiPage1.Pages((m_colSteps("1").Page) - 1).Caption = m_colSteps("1").Caption m_oWizard.HandleControls iPageCount = MultiPage1.Pages.Count For i = 1 To iPageCount - 1 MultiPage1.Pages(i).Visible = False NextEnd Sub

這里,設置多頁控件的Value屬性為PageSetting集合(m_colSteps)的項目(其鍵值為1),并設置其標題:

iFirstPage = m_colSteps("1").Order - 1 Me.MultiPage1.Value = iFirstPage Me.MultiPage1.Pages((m_colSteps("1").Page) - 1).Caption = m_colSteps("1").Caption

記住,我們傳遞Order屬性的值作為鍵值,這使得它非常容易去判斷要移動至哪頁。當設置多頁控件的Value屬性時,正使用相對應的值激活該頁。在這里,該值為1.
然后調用m_oWizard對象的HandleControls方法初始化導航按鈕為正確的設置:

m_oWizard.HandleControls

接下來,隱藏除第一頁外的所有頁:

iPageCount = MultiPage1.Pages.Count For i = 1 To iPageCount - 1 MultiPage1.Pages(i).Visible = False Next

記住,多頁控件的Page集合是基于0的,因此通過以1開始循環計數器,保持該頁面可見。
此時,可以運行用戶窗體。
1、在VBE中,雙擊工程資源管理器窗口的用戶窗體。
2、單擊標準工具欄中的“運行子過程/用戶窗體”按鈕或者按F5鍵,如下圖所示。

注意,下圖中在選項卡中出現的標題,并且前一步按鈕被禁用。

再看看Department組合框,綁定Departments命名區域到該組合框。

3、通過單擊右上方的X按鈕,停止用戶窗體的運行。
給用戶窗體添加導航
導航按鈕在向導應用程序中具有移動步驟的任務。但它們也需要放置每個屏幕中的數據到其在用戶窗體的cPerson對象里的位置的能力。
在cmdNext_Click中添加下列代碼:

Private Sub cmdNext_Click() Dim iNext As Integer StoreData iNext = m_oWizard.NextPage Me.MultiPage1.Value = m_colSteps(CStr(iNext)).Order - 1 Me.MultiPage1.Pages((m_colSteps(CStr(iNext)).Page) - 1).Caption = m_colSteps(CStr(iNext)).Caption ShowNextPage "up"End Sub

在向導中移到下一步之前首先需要做的是,保留在當前用戶窗體中輸入的值。StoreData方法決定用戶處于哪一步并基于該位置調用正確的存儲方法,代碼如下所示:

Private Sub StoreData() Select Case m_oWizard.CurrentPage Case 1 StorePerson Case 2 StoreAddress Case 3 StoreEquipment Case 4 StoreAccess End SelectEnd Sub

上述代碼中的存儲方法的代碼如下:

Private Sub StorePerson() With m_oEmployee .FName = Me.txtFname.Value .MidInit = Me.txtMidInit.Value .LName = Me.txtLname.Value If Len(Me.txtDOB.Value & "") > 0 Then .DOB = Me.txtDOB.Value End If .SSN = Me.txtSSN.Value .Department = Me.cboDept.Text .JobTitle = Me.txtJobTitle.Value .Email = Me.txtEmail.Value End WithEnd Sub Private Sub StoreAddress() With m_oEmployee.Address .StreetAddress = Me.txtStreetAddr.Value .StreetAddress2 = Me.txtStreetAddr2.Value .City = Me.txtCity.Value .State = Me.txtState.Value .ZipCode = Me.txtZip.Value .PhoneNumber = Me.txtPhone.Value .CellPhone = Me.txtCell.Value End WithEnd Sub Private Sub StoreEquipment() Dim opt As MSForms.OptionButton With m_oEmployee.Equipment For Each opt In Me.fraPCType.Controls If opt.Value = True Then .PCType = opt.Caption Exit For End If Next  For Each opt In Me.fraPhoneType.Controls If opt.Value = True Then .PhoneType = opt.Caption Exit For End If Next  .Location = Me.cboLocation.Text  If Me.chkFaxYN = True Then .FaxYN = "Y" Else .FaxYN = "N" End If End WithEnd Sub Private Sub StoreAccess() Dim opt As MSForms.OptionButton With m_oEmployee.Access If Len(Me.cboNetworkLvl.Text & "") > 0 Then .NetworkLevel = CInt(Me.cboNetworkLvl.Text) End If .ParkingSpot = Me.cboParkingSpot.Text .RemoteYN = Me.cboRemoteAccess.Text For Each opt In Me.fraBuilding.Controls If opt.Value = True Then .Building = opt.Caption Exit For End If Next End WithEnd Sub

這段代碼簡單地從屏幕中接收數據,并將其放置在cPerson里的相應的對象中。
接下來,確定下一頁。(記住,多頁集合是基于0的,因此從Order屬性中減1以獲得下一頁的值)

iNext = m_oWizard.NextPage Me.MultiPage1.Value = m_colSteps(CStr(iNext)).Order - 1 Me.MultiPage1.Pages((m_colSteps(CStr(iNext)).Page) - 1).Caption = m_colSteps(CStr(iNext)).Caption

然后,調用ShowNextPage方法,告訴它我們想移動的方式:

ShowNextPage "up"

ShowNextPage方法的代碼如下:

Private Sub ShowNextPage(Direction As String) Dim iCurrPage As Integer Dim iUpDown As Integer iCurrPage = MultiPage1.Value If LCase(Direction) = "up" Then iUpDown = 1 Else iUpDown = -1 End If MultiPage1.Pages(iCurrPage + iUpDown).Visible = True MultiPage1.Pages(iCurrPage).Visible = FalseEnd Sub

這個方法查找CurrentPage屬性的值,基于傳遞給該方法的Direction參數加或減1。
cmdPrevious按鈕的Click事件看起來非常相似:

Private Sub cmdPrevious_Click() Dim iPrevious As Integer StoreData iPrevious = m_oWizard.PreviousPage Me.MultiPage1.Value = m_colSteps(CStr(iPrevious)).Order - 1 Me.MultiPage1.Pages((m_colSteps(CStr(iPrevious)).Page) - 1).Caption = m_colSteps(CStr(iPrevious)).Caption ShowNextPage "down"End Sub

唯一的差別是傳遞關鍵字down到ShowNextPage方法以便向用戶移動到合適的方向。
下面,添加最后一個事件處理來幫助我們使用導航。無論何時改變多頁控件中的頁面,控件的Change事件被觸發。我們使用事件去捕捉當前頁面的值,并將其存儲在m_oWizard對象的CurrentPage屬性中。
添加下面的代碼到MultiPage1控件的Change事件:

Private Sub MultiPage1_Change() m_oWizard.CurrentPage = MultiPage1.Value + 1End Sub

現在,讓我們來試試導航的工作。
1、在設計視圖下打開用戶窗體,單擊標準工具欄中的“運行子程序/用戶窗體”按鈕或按F5鍵。
2、打開用戶窗體后,單擊下一步按鈕移動到向導中的第二步(已在配置工作表中定義),應該是Address屏幕。注意到兩個導航按鈕現在都能用了,如下圖所示。

3、單擊前一步按鈕導航回到Personal屏幕,此時前一步按鈕不再是活動的了。
4、單擊下一步按鈕直至最后一個屏幕(已在配置工作表中定義),應該是NetWork Access屏幕,此時下一步按鈕不再能夠使用,如下圖所示。

5、通過單擊右上方的X按鈕,停止用戶窗體的運行。
保存員工記錄
至此,我們已經做了大量的工作,獲得了一些完美干凈的功能從自定義對象提供給用戶窗體。唯一沒有做的就是將數據保存到EmpData工作表。
一般來說,可以創建一個子程序,將其命名如SaveData(),將從cmdSave_Click事件中調用該程序,但是cHRData類已經具有了SaveEmployee方法。我們可以直接從cmdSave_Click中調用而不需要再創建保存函數。
在cmdSave_Click事件中插入下列代碼:

Private Sub cmdSave_Click() Dim oHRData As cHRData Set oHRData = New cHRData Set oHRData.Worksheet = Sheets("EmpData") oHRData.SaveEmployee m_oEmployee Set oHRData = NothingEnd Sub

在設置Worksheet屬性之后,以便于cHRData對象知道在哪里保存數據,調用SaveEmployee方法,傳遞m_oEmployee對象,那里包含要保存的所有數據。
清理
我們幾乎已經獲得了一個完整的應用程序。下面讓我們添加Cancel按鈕的代碼并在用戶窗體的Terminate事件中放置清理代碼。
在cmdCancel按鈕的Click事件中添加下面的代碼行:

Private Sub cmdCancel_Click() Unload MeEnd Sub

這行代碼簡單地卸載用戶窗體而不保存任何數據。
現在我們清除HRWizard用戶窗體使用的對象。在UserForm_Terminate事件處理中添加下列代碼:

Private Sub UserForm_Terminate() Set m_oEmployee = Nothing Set m_oLM = Nothing Set m_oWizard = NothingEnd Sub

下面再添加一個簡單的函數用來打開向導窗體。在VBE中,添加一個標準模塊,在其中添加下列代碼:

Sub StartWizard() HRWizard.ShowEnd Sub

測試HRWizard應用程序
測試時間到了!我們在向導中的每一屏幕中輸入數據,并將其保存到EmpData工作表中。
從Excel工作簿中,從宏對話框中運行StartWizard子程序,如下圖所示。

下圖中顯示了一些簡單的輸入值以及在EmpData工作表中保存的數據。




學習小結






歡迎光臨 (http://www.raoushi.com/bbs/) Powered by Discuz! X3.1