類 | 描述 |
---|---|
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屬性
類 | 描述 |
---|---|
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屬性
類 | 描述 |
---|---|
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 |
上述代碼完成下列工作:
Set .Worksheet = Sheets("UFormConfig") |
.NumberOfSettings = 3 |
Set m_colSteps = .PageSettings |
Set .PreviousButton = Me.cmdPreviousSet .NextButton = Me.cmdNext |
.CurrentPage = MultiPage1.Value + 1 |
因為多頁控件的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 |