2016-11-29 118 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

相关问题