2016-11-29 76 views
0

在我65人的辦公室裏,我想爲所有員工創建一個「門戶」,只需一個.accdb文件。它將允許每位員工從下拉菜單導航到新的「屏幕」。我應該重新使用一個窗體上的子窗體控件還是隻創建多個窗體?

我應該使用帶有即插即用子窗體控件的單一窗體來集中VBA代碼,還是應該只使用不同的窗體?

我想這將是很好,有一個形式與即插即用子窗體控件。當員工選擇新的「屏幕」時,VBA只設置每個子窗體控件的SourceObject屬性,然後根據所選「屏幕」的佈局重新排列子窗體。例如,我們目前使用一對Access數據庫表單來輸入和查看我們在工作流系統中發現的錯誤。因此,在這種情況下,檢討錯誤,我只想說

SubForm1.SourceObject = "Form.ErrorCriteria" 
SubForm2.SourceObject = "Form.ErrorResults" 

然後,我只想將它們移動到的地方(這些值將被動態地拉到根據所選擇的「屏」):

SubForm1.Move WindowWidth * 0.05, WindowHeight * 0.05, WindowWidth * 0.9, WindowHeight * 0.2 
SubForm2.Move WindowWidth * 0.05, WindowHeight * 0.25, WindowWidth * 0.9, WindowHeight * 0.65 

因此,這將在窗體上創建一個小標題部分(SubForm1),我可以選擇我想要查看的錯誤的標準(數據範圍,哪個團隊提交錯誤等),然後我可以查看錯誤標題下面的較大部分(SubForm2)將結果保存在數據表中。

我可以將事件傳播到ErrorCriteriaErrorResults現在綁定到子窗體控件的窗體中。這將幫助我使用描述爲here的VBA的基本MVC設計模式。我可以將主窗體視爲視圖,即使部分視圖隱藏在子窗體控件中。控制器只需要知道那個視圖。

我的問題出現在用戶從下拉菜單中選擇一個新的「屏幕」。我認爲這將是很好,只是重新利用子窗體控件,就像這樣:

SubForm1.SourceObject = "Form.WarehouseCriteria" 
SubForm2.SourceObject = "Form.InventoryResults" 

然後就是移動/調整這些子窗體到適當的佈局爲「庫存」屏幕。

這種方法似乎讓用戶界面設計更清晰,因爲您基本上只需處理一個充當模板的主窗體,然後將值(SourceObject屬性)插入到該模板中。

但是,每次我們更改「屏幕」時,根據MVC設計模式,我們在幕後都會有一個完全不同的「模型」,並且會有一個新的「視圖」。我想知道是否會在幕後干擾MVC VBA代碼,或者如果VBA代碼本身也可能被模塊化(可能使用接口)以使其與用戶界面一樣適應。

從用戶界面的角度和從VBA的角度來看,最簡單的方法是什麼?使用一個主窗體作爲模板,其他窗體可以作爲子窗體交換進出,或者只需關閉當前窗體並在用戶從下拉菜單中選擇新的「屏幕」時打開一個新窗體。

+0

首先,我當然希望你有一個前端/後端設置,如果你有65人!要在表單界面上給出建議,它取決於您擁有的控件的數量/複雜程度。我們開發了一個「報告界面」,根據用戶的角色,他們可以看到從1到20個過濾器(控件)的任何地方,因此使用了一個帶有「地圖」表的表單。你的表格有多複雜? –

+0

是的,它是一個分割數據庫。你如何使用該地圖表?聽起來不錯。 – BarrettNashville

+0

映射表包含字段:ID(PK),ReportName,CtlName,CtlOrder,CtlTop,CtlLeft,SkipLabel(Bool),CtlRecordSource。除非報告使用,否則所有ctls都是隱藏的。當用戶從組合框中選擇報告時,將從地圖表中檢索到的字段列表和表單被更改。 –

回答

1

下面簡單介紹一種「重新調整用途」或重新格式化多種用途的方法。關於更改VBA代碼的問題,一個簡單的解決方案是檢查標籤值或您在控件中設置的某個值,然後調用相應的VBA子例程。

我們有超過100個報告,每個都有自己的選擇標準/選項和我們不希望創建的每個報告的唯一過濾器的形式。解決方案是識別報告可用的選擇選項,確定這些選項的邏輯順序,然後創建一個向用戶顯示選項的表格。

首先,我們創建了表:ctlReportOptions(PK = ID,ReportName,OptionOrder) 字段:ID(Int),ReportName(文本),OptionOrder(Int),ControlName(文本),ControlTop(Int),ControlLeft (Int),SkipLabel(是/否),ControlRecordsourc(文本) 注1:ID不是自動編號。

接下來我們用定義用戶將看到的視圖的記錄填充。 注2:使用零ID,我們爲報表上的EVERY字段創建記錄,以便我們隨時可以爲開發人員重新繪製記錄。

然後我們創建了窗體併爲每個可能的過濾器放置了控件。 我們設置'默認值'屬性作爲默認值。

一些控件: 組合框來選擇報告名稱。對於更改事件添加代碼如下:

Private Sub cboChooseReport_Change() 
Dim strSQL  As String 
Dim rs   As ADODB.recordSet 
Dim i   As Integer 
Dim iTop  As Integer 
Dim iLeft  As Integer 
Dim iLblTop  As Integer 
Dim iLblLeft As Integer 
Dim iLblWidth As Integer 
Dim iTab  As Integer 
Dim strLabel As String 

    On Error GoTo Error_Trap 
    ' Select only optional controls (ID <> 0); skip cotrols always present. 
    strSQL = "SELECT ctlRptOpt.ControlName, 'lbl' & Mid([ControlName],4,99) AS LabelName, SkipLabel " & _ 
       "From ctlRptOpt WHERE (((ctlRptOpt.ID)<>0)) " & _ 
       "GROUP BY ctlRptOpt.ControlName, 'lbl' & Mid([ControlName],4,99), SkipLabel;" 
    Set rs = New ADODB.recordSet 
    rs.Open strSQL, CurrentProject.Connection, adOpenDynamic 

    Do While Not rs.EOF 
     Me(rs!ControlName).Visible = False  ' Hide control 
     If rs!skiplabel = False Then   ' Hide Label if necessary 
      Me(rs!LabelName).Visible = False 
     End If 
     rs.MoveNext 
    Loop 
    rs.Close 

    iTop = 0 
    iTab = 0 

    ' Get list of controls used by this report; order by desired sequence. 
    strSQL = "select * from ctlRptOpt " & _ 
       "where [ID] = " & Me.cboChooseReport.Column(3) & _ 
       " order by OptionOrder;" 
    Set rs = New ADODB.recordSet 
    rs.Open strSQL, CurrentProject.Connection, adOpenDynamic 

    If rs.EOF Then  ' No options needed 
     Me.cmdShowQuery.Visible = True 
     Me.lblReportCriteria.Visible = False 
     Me.cmdShowQuery.left = 2000 
     Me.cmdShowQuery.top = 1500 
     Me.cmdShowQuery.TabIndex = 1 
     Me.cmdReset.Visible = False 
     rs.Close 
     Set rs = Nothing 
     GoTo Proc_Exit    ' Exit 
    End If 

    ' Setup the display of controls. 
    Me.lblReportCriteria.Visible = True 
    Do While Not rs.EOF 
     If rs!skiplabel = False Then 
      strLabel = "lbl" & Mid(rs!ControlName, 4) 
      iLblWidth = Me.Controls(strLabel).Width 
      Me(strLabel).top = rs!ControlTop 
      Me(strLabel).left = rs!ControlLeft - (Me(strLabel).Width + 50) 
      Me(strLabel).Visible = True 
     End If 

     iTab = iTab + 1   ' Set new Tab Order for the controls 
     Me(rs!ControlName).top = rs!ControlTop 
     Me(rs!ControlName).left = rs!ControlLeft 
     Me(rs!ControlName).Visible = True 
     If left(rs!ControlName, 3) <> "lbl" Then 
      Me(rs!ControlName).TabIndex = iTab 
     End If 

     If Me(rs!ControlName).top >= iTop Then 
      iTop = rs!ControlTop + Me(rs!ControlName).Height   ' Save last one 
     End If 

     ' If not a label and not a 'cmd', it's a filter! Set a default. 
     If left(rs!ControlName, 3) <> "lbl" And left(rs!ControlName, 3) <> "cmd" Then 
      If Me(rs!ControlName).DefaultValue = "=""*""" Then 
'    Me(rs!ControlName) = "*" 
      ElseIf left(Me(rs!ControlName).DefaultValue, 2) = "=#" And right(Me(rs!ControlName).DefaultValue, 1) = "#" Then 
       i = Len(Me(rs!ControlName).DefaultValue) 
'    Me(rs!ControlName) = Mid(Me(rs!ControlName).DefaultValue, 3, i - 3) 
      ElseIf Me(rs!ControlName).DefaultValue = "True" Then 
'    Me(rs!ControlName) = True 
      ElseIf Me(rs!ControlName).DefaultValue = "False" Then 
'    Me(rs!ControlName) = False 
      End If 
     Else 
      If Me(rs!ControlName).top + Me(rs!ControlName).Height >= iTop Then 
       iTop = rs!ControlTop + Me(rs!ControlName).Height   ' Save last one 
      End If 
     End If 
     rs.MoveNext 
    Loop 
    rs.Close 
    Set rs = Nothing 

    If Me.cboChooseReport.Column(1) <> "rptInventoryByDate" Then  ' It's special 
     Me.cmdShowQuery.Visible = True 
     Me.cmdShowQuery.left = 2000 
     Me.cmdShowQuery.top = iTop + 300 
     iTab = iTab + 1 
     Me.cmdShowQuery.TabIndex = iTab 
    Else 
     Me.cmdShowQuery.Visible = False 
    End If 
    Me.cmdReset.Visible = True 
    Me.cmdReset.left = 5000 
    Me.cmdReset.top = iTop + 300 
    Me.cmdReset.TabIndex = iTab + 1 

Proc_Exit: 
    Exit Sub 
Error_Trap: 
    Err.Source = "Form_frmReportChooser: cboChooseReport_Change at Line: " & Erl 
    DocAndShowError  ' Save error to database for analysis, then display to user. 
    Resume Proc_Exit ' Exit code. 
    Resume Next   ' All resumption if debugging. 
    Resume 
End Sub 

lblReportCriteria:我們顯示的最後一組過濾器,這樣當用戶抱怨沒有顯示在報告中,我們要求他們給我們發送絲網印刷。我們還將此文本傳遞給報告,並在最後一頁打印爲頁腳。

cmdReset:將所有控件重置爲其默認值。

cmdShowQuery:執行報告

Private Sub cmdShowQuery_Click()  
Dim qdfDelReport101    As ADODB.Command 
Dim qdfAppReport101    As ADODB.Command 
Dim qdfDelReport102    As ADODB.Command 
Dim qdfAppReport102    As ADODB.Command 
Dim qryBase      As ADODB.Command 
Dim strQueryName    As String 
Dim strAny_Open_Reports   As String 
Dim strOpen_Report    As String 
Dim qdfVendorsInfo    As ADODB.Command 
Dim rsVendorName    As ADODB.recordSet 
Dim strVendorName    As String 
Dim rsrpqFormVendorsInfo  As ADODB.recordSet 

    On Error GoTo Error_Trap 
    If Not IsNull(Me.cboChooseReport.value) And Me.cboChooseReport.value <> " " Then 
     strAny_Open_Reports = Any_Open_Reports() 
     If Len(strAny_Open_Reports) = 0 Then 

      If Me.cboChooseReport.value = "rptAAA" Then 
       BuildReportCriteria     ' 
       If Me.chkBankBal = True Then 
        DoCmd.OpenReport "rptAAA_Opt1", acViewPreview 
       Else 
        DoCmd.OpenReport "rptAAA_Opt2", acViewPreview 
       End If 
      ElseIf Me.cboChooseReport.value = "rptBBB" Then 
       If IsNull(Me.txtFromDate) Or Not IsDate(Me.txtFromDate) Then 
        MsgBox "You must enter a valid From Date", vbOKOnly, "Invalid Date" 
        Exit Sub 
       End If 
       If IsNull(Me.txtToDate) Or Not IsDate(Me.txtToDate) Then 
        MsgBox "You must enter a valid To Date", vbOKOnly, "Invalid Date" 
        Exit Sub 
       End If 

       Me.txtStartDate = Me.txtFromDate 
       Me.txtEndDate = Me.txtToDate 
       DoCmd.OpenReport Me.cboChooseReport.value, acViewPreview 
      ElseIf Me.cboChooseReport.value = "rptCCC" Then 
       If Me.txtVendorName = "*" Then 
        gvstr_VendorName = "*" 
       Else 
        Set rsVendorName = New ADODB.recordSet 
        rsVendorName.Open "selVendorName", gv_DBS_Local, adOpenDynamic 

        Set qdfVendorsInfo = New ADODB.Command 
        qdfVendorsInfo.ActiveConnection = gv_DBS_SQLServer 
        qdfVendorsInfo.CommandText = ("qryVendorsInfo") 
        qdfVendorsInfo.CommandType = adCmdStoredProc 
        strVendorName = rsVendorName("VendorName") 
        gvstr_VendorName = strVendorName 
       End If 
       DoCmd.OpenReport "rptFormVendorReport", acViewPreview 
      Else 
       BuildReportCriteria 
       If Me.cboChooseReport.value = "rptXXXXXX" Then 
       ElseIf Me.cboChooseReport.value = "rptyyyy" Then 
        On Error Resume Next   ' All resumption if debugging. 
        DoCmd.DeleteObject acTable, "temp_xxxx" 
        On Error GoTo Error_Trap 
        Set qryBase = New ADODB.Command 
        qryBase.ActiveConnection = gv_DBS_Local 
        qryBase.CommandText = ("mtseldata...") 
        qryBase.CommandType = adCmdStoredProc 
        qryBase.Execute 
       End If 
       DoCmd.Hourglass False 
       DoCmd.OpenReport Me.cboChooseReport.value, acViewPreview 
      End If 
     Else 
      MsgBox "You cannot open this form/report because you already have a form/report(s) open: " & _ 
        vbCrLf & strAny_Open_Reports & _ 
        vbCrLf & "Please close the open form/report(s) before continuing." 

      strOpen_Report = Open_Report 
      DoCmd.SelectObject acReport, strOpen_Report 
      DoCmd.ShowToolbar "tbForPost" 
     End If 
    Else 
     MsgBox "Please Choose Report", vbExclamation, "Choose Report" 
    End If 

    Exit Sub 

Error_Trap: 
    Err.Source = "Form_frmReportChooser: cmdShowQuery_Click - Report: " & Nz(Me.cboChooseReport.value) & " at Line: " & Erl 
    If Err.Number = 2501 Then ' MsgBox "You chose not to open this report.", vbOKOnly, "Report cancelled" 
     Exit Sub 
    ElseIf Err.Number = 0 Or Err.Number = 7874 Then 
     Resume Next   ' All resumption if debugging. 

    ElseIf Err.Number = 3146 Then ' ODBC -- call failed -- can have multiple errors 
Dim errLoop  As Error 
Dim strError As String 
Dim Errs1  As Errors 

    ' Enumerate Errors collection and display properties of each Error object. 
    i = 1 
     Set Errs1 = gv_DBS_SQLServer.Errors 
     Err.Description = Err.Description & "; Err.Count = " & gv_DBS_SQLServer.Errors.Count & "; " 
     For Each errLoop In Errs1 
      With errLoop 
       Err.Description = Err.Description & "Error #" & i & ":" & " ADO Error#" & .Number & _ 
         " Description= " & .Description 
       i = i + 1 
      End With 
     Next 

    End If 
    DocAndShowError  ' Save error to database for analysis, then display to user. 
    Exit Sub 
    Resume Next   ' All resumption if debugging. 
    Resume 
End Sub 

功能運行構建出所有的選擇標準的字符串:

Function BuildReportCriteria() 
Dim frmMe   As Form 
Dim ctlEach   As Control 
Dim strCriteria  As String 
Dim prp    As Property 
Dim strSQL   As String 
Dim rs    As ADODB.recordSet 

    On Error GoTo Error_Trap 

    strSQL = "select * from ctlRptOpt " & _ 
       "where ID = " & Me.cboChooseReport.Column(3) & _ 
       " order by OptionOrder;" 
    Set rs = New ADODB.recordSet 
    rs.Open strSQL, CurrentProject.Connection, adOpenDynamic 

    If rs.EOF Then 
     strCriteria = "  Report Criteria: None" 
    Else 
     strCriteria = "  Report Criteria: " 
    End If 

    Do While Not rs.EOF 
     Set ctlEach = Me.Controls(rs!ControlName) 
     If ctlEach.ControlType = acTextBox Or ctlEach.ControlType = acComboBox Then 
      If ctlEach.value <> "*" And ctlEach.Name <> "cboChooseReport" And ctlEach.Name <> "cboLocCountry" Then 
       strCriteria = strCriteria & ctlEach.Tag & " = " & ctlEach.value & " , " 
      End If 
     End If 
     rs.MoveNext 
    Loop 
    rs.Close 
    Set rs = Nothing 

    If Me.chkOblBal = -1 Then 
     strCriteria = strCriteria & "Non-zero balances only = Yes" 
    Else 
    'return string with all choosen criteria and remove last " , " from the end of string 
     strCriteria = left$(strCriteria, Len(strCriteria) - 3) 
    End If 
    fvstr_ReportCriteria = strCriteria 

    Set ctlEach = Nothing 

    Exit Function 
Error_Trap: 
    If Err.Number = 2447 Then 
     Resume Next   ' All resumption if debugging. 
    End If 
    Err.Source = "Form_frmReportChooser: BuildReportCriteria at Line: " & Erl 
    DocAndShowError  ' Save error to database for analysis, then display to user. 
    Exit Function 
    Resume Next   ' All resumption if debugging. 
End Function 

最後,每個報告有它自己的查詢,將過濾器的基礎在此窗體上的控件中的值。

希望這會有所幫助。如果你對你看到的任何奇怪的事情感到好奇,請告訴我。 (即我們總是在代碼中使用行號(我在發佈前刪除),使我們能夠在那裏代碼無法確定確切的行)

+0

爲什麼使用MS Access的ADOB?建議使用DAO,速度要快得多。 ADODB確實有它的位置,但並非總是如此。 – Fionnuala

+0

我們從Access遷移到SQL Server,因此ADO的東西:)我同意DAO並將其作爲我的第一選擇! –

+0

感謝您的詳細解答!我需要一些時間才能解決這個問題,但它解決了我正在努力解決的確切問題。 – BarrettNashville

相關問題