Arrays 使用excel检查表数据在新工作表中创建和填充列表的有效方法

Arrays 使用excel检查表数据在新工作表中创建和填充列表的有效方法,arrays,vba,excel,Arrays,Vba,Excel,我正在做一个项目,它接受用户创建并填写的检查表 并且,当用户运行宏时,会创建一个新工作簿,用于推断和扩展检查表数据,如下所示 它所做的是遍历每个数字人工代码,并运行所有适用项目的检查表,将它们添加到列表中 现在…我已经很好地工作了,并且通过了基本的测试。我将检查表保存为数组,并将其传递到新工作簿,逐行筛选和创建新工作簿 我只是忍不住想,有一种更简单的方法可以做到这一点,因为我现在这样做似乎不是最简单、最稳定的方法 我很乐意分享我的代码,但我想知道如果你有这个senario,你会如何处理它 以

我正在做一个项目,它接受用户创建并填写的检查表

并且,当用户运行宏时,会创建一个新工作簿,用于推断和扩展检查表数据,如下所示

它所做的是遍历每个数字人工代码,并运行所有适用项目的检查表,将它们添加到列表中

现在…我已经很好地工作了,并且通过了基本的测试。我将检查表保存为数组,并将其传递到新工作簿,逐行筛选和创建新工作簿

我只是忍不住想,有一种更简单的方法可以做到这一点,因为我现在这样做似乎不是最简单、最稳定的方法

我很乐意分享我的代码,但我想知道如果你有这个senario,你会如何处理它

以下是指向我的文件的链接:

主模块,用于检查错误并更正格式:

Option Explicit
    Public FamilyName As String
    Public ModelName As String
    Public TaskArray() As Variant
    Public TaskArrayRowCount As Integer
    Public TaskArrayColCount As Integer

Sub CreateTemplate()
    Application.EnableEvents = False
    Application.ScreenUpdating = False
'Main SubModule. Runs Formatting and Template Generation
    Dim thisWB As Workbook
    Dim TaskArray() As Variant
    Dim i As Range
    Dim MajMinYesNo As Boolean
    Dim OPOYesNo As Boolean

    If MsgBox("Are you ready to generate the Template?", vbYesNo, "Ready?") = vbNo Then
        Application.EnableEvents = True
        Application.ScreenUpdating = True
        End
    End If

    MajMinYesNo = False
    OPOYesNo = False
    Set thisWB = ActiveWorkbook
    FamilyName = thisWB.Names("Family_Name").RefersToRange
    ModelName = thisWB.Names("Model_No").RefersToRange

    Call CreateArray(thisWB)
    'Scans Form_Type Column for "R", "S", or "A-E"
    For Each i In Range("CS_FormType")
        If i Like "[RS]" Then
            MajMinYesNo = True
        ElseIf i Like "[A-E]" Then
            OPOYesNo = True
        End If
    Next

    'Generates Templates As Needed
    If MajMinYesNo Then
        If MsgBox("Generate Major/Minor Template?", vbYesNo) = vbYes Then
            Call MajorMinor_Generate.GenerateMajorMinor(thisWB)
        End If
    End If
    If OPOYesNo Then
        If MsgBox("Generate OPO Template?", vbYesNo) = vbYes Then
        Call OPO_Generate.GenerateOPO(thisWB)
        End If
    End If
    Application.EnableEvents = True
    Application.ScreenUpdating = True
    MsgBox ("DONE!")
End Sub
Sub CreateArray(thisWB As Workbook)
'Checks formatting and creates array TaskArray() with all the checksheet data

    With thisWB.Sheets(1)
    'Confirms equal number of rows in columns "CS_TaskNo", "CS_FormType", and "CS_Task"
        If (Not Range("CS_TaskNo").Rows.count = Range("CS_FormType").Rows.count) _
            Or (Not Range("CS_TaskNo").Rows.count = Range("CS_Task").Rows.count) Then
            MsgBox ("Task_No, Form_Type, and Task_Desc row count does not match. Please fix and try again")
            Application.EnableEvents = True
            Application.ScreenUpdating = True
            End
        End If
        Call FormatCheck

        Application.Union(Range("CS_Heading"), Range("CS_TaskNo"), Range("CS_FormType"), Range("CS_Task"), Range("CS_LaborCodes"), Range("CS_Checks")).Name = "TaskArray"
        TaskArrayRowCount = Range("TaskArray").Rows.count
        TaskArrayColCount = Range("TaskArray").Columns.count
        ReDim TaskArray(TaskArrayRowCount, TaskArrayColCount)
        TaskArray = Range("TaskArray").Value
    End With
End Sub
Sub FormatCheck()
'Checks for valid labor codes and Form Types
    If (Not CheckFormType()) Or (Not CheckLC()) Then
        MsgBox ("Errors found, please check red-highlighted cells")
        Application.EnableEvents = True
        Application.ScreenUpdating = True
        End
    End If
End Sub
Function CheckFormType()
'Returns False if there's a bad Form_Type entry in range "CS_FormType", True if all OK
    Dim i As Range
    Dim ReturnVal As Boolean

    ReturnVal = True
    For Each i In Range("CS_FormType")
        Trim (UCase(i.Value))
        If Not (i Like "[ABCDEFRS]") Then
            Highlight (Cells(i.Row, i.Column))
            ReturnVal = False
        End If
    Next
    CheckFormType = ReturnVal
End Function
Function CheckLC()
'Returns False if there's a bad error code, True if all OK _
Formats labor code ranges to add spaces as needed and checks _
labor codes for proper format (###X or ##X). Skips any labor _
codes starting with "28X"

    Dim LaborCode As String
    Dim LaborCodeLength As Integer
    Dim i As Range
    Dim j As Integer
    Dim LCCell As Range
    Dim LCArray() As String
    Dim ReturnVal As Boolean

    ReturnVal = True

    For Each i In Range("CS_LaborCodes")
        Trim (UCase(i.Value))
        LaborCode = i.Value
        If Not Left(LaborCode, 3) Like "28?" Then
            LaborCodeLength = Len(LaborCode)
            'If string LaborCode is > 4, safe to assume it is a range of labor codes 123A-123F
            Select Case LaborCodeLength
            Case Is > 4
                'Formats Labor Code Range String by adding spaces if necessary (i.e. 123A-123F to 123A - 123F)
                For j = 2 To LaborCodeLength Step 1
                    If (IsNumeric(Mid(LaborCode, j, 1))) And Not IsNumeric(Mid(LaborCode, j + 1, 1)) And Not (Mid(LaborCode, j + 2, 1) = " ") Then
                        LaborCode = Left(LaborCode, j + 1) & " " & Mid(LaborCode, j + 2)
                    ElseIf IsNumeric(Mid(LaborCode, j, 1)) And Not (Mid(LaborCode, j - 1, 1) = " ") And Not IsNumeric(Mid(LaborCode, j - 1, 1)) Then
                        LaborCode = Left(LaborCode, j - 1) & " " & Mid(LaborCode, j)
                    End If
                Next
                i = LaborCode
                LCArray = Split(LaborCode, " ")
                'confirms the labor codes are valid
                If (Not IsLaborCode(LCArray(0))) Or (Not IsLaborCode(LCArray(2))) Or (Not IsLaborCodeRange(LCArray(0), LCArray(2))) Then
                    Highlight (Cells(i.Row, i.Column))
                    ReturnVal = False
                End If
            Case 0 To 4
                If Not (IsLaborCode(LaborCode)) Then
                    Highlight (Cells(i.Row, i.Column))
                    ReturnVal = False
                End If
            Case Else
                Highlight (Cells(i.Row, i.Column))
                ReturnVal = False
            End Select
        End If
    Next
    CheckLC = ReturnVal
End Function
Function IsLaborCode(LC As String) As Boolean
'returns True if Labor Code is valid, False if invalid _
Labor Code is valid if it is 2 or 3 numbers followed by a letter _
labor code format : ###X or ##X
    If LC Like "###[A-Z]" Or LC Like "##[A-Z]" Then
        IsLaborCode = True
    Else
        IsLaborCode = False
    End If
End Function
Function IsLaborCodeRange(LCOne As String, LCTwo As String) As Boolean
'returns True if the LC range is valid, False if invalid. _
checks the numerical values to make sure they match and _
makes sure the letters are ascending
    If (StrComp(Left(LCOne, Len(LCOne) - 1), Left(LCTwo, Len(LCTwo) - 1)) = 0) And LCOne < LCTwo Then
        IsLaborCodeRange = True
    Else
        IsLaborCodeRange = False
    End If
End Function
选项显式
作为字符串的公共FamilyName
作为字符串的公共模型名
作为变量的公共TaskArray()
公共任务ArrayRowCount为整数
公共任务ArrayColCount为整数
子CreateTemplate()
Application.EnableEvents=False
Application.ScreenUpdating=False
'主子模块。运行格式化和模板生成
将此WB设置为工作簿
Dim TaskArray()作为变量
暗i作为范围
Dim MajMinYesNo作为布尔值
Dim OPOYesNo作为布尔
如果MsgBox(“您准备好生成模板了吗?”,vbYesNo,“准备好了吗?”)=vbNo,则
Application.EnableEvents=True
Application.ScreenUpdating=True
终点
如果结束
MajMinYesNo=错误
OPOYesNo=假
设置thisWB=ActiveWorkbook
FamilyName=thisWB.Names(“Family_Name”).refrestorange
ModelName=thisWB.Names(“型号”).refrestorange
调用CreateArray(thisWB)
'扫描“R”、“S”或“A-E”的表格类型列
对于范围内的每个i(“CS_FormType”)
如果我喜欢“[RS]”那么
MajMinYesNo=真
如果我喜欢“[A-E]”那么
OPOYesNo=正确
如果结束
下一个
'根据需要生成模板
如果没有,那么
如果MsgBox(“生成主要/次要模板?”,vbYesNo)=vbYes,则
调用MajorMinor_Generate.generateMarjorMinor(thisWB)
如果结束
如果结束
如果是OPOYesNo那么
如果MsgBox(“生成OPO模板?”,vbYesNo)=vbYes,则
调用OPO_Generate.generatePo(thisWB)
如果结束
如果结束
Application.EnableEvents=True
Application.ScreenUpdating=True
MsgBox(“完成!”)
端接头
子CreateArray(此WB作为工作簿)
'检查格式并使用所有检查表数据创建数组TaskArray()
使用此WB.表(1)
'确认“CS_TaskNo”、“CS_FormType”和“CS_Task”列中的行数相等'
If(非范围(“CS_TaskNo”).Rows.count=范围(“CS_FormType”).Rows.count)_
或者(非范围(“CS_任务号”).Rows.count=范围(“CS_任务”).Rows.count),然后
MsgBox(“任务编号、表单类型和任务描述行计数不匹配。请修复并重试”)
Application.EnableEvents=True
Application.ScreenUpdating=True
终点
如果结束
呼叫格式检查
应用程序.Union(范围(“CS\u标题”)、范围(“CS\u任务编号”)、范围(“CS\u表单类型”)、范围(“CS\u任务”)、范围(“CS\u代码”)、范围(“CS\u检查”)。Name=“TaskArray”
TaskArrayRowCount=范围(“TaskArray”).Rows.count
TaskArrayColCount=范围(“TaskArray”).Columns.count
ReDim TaskArray(TaskArrayRowCount、TaskArrayColCount)
TaskArray=范围(“TaskArray”)。值
以
端接头
子格式检查()
'检查有效的人工代码和表单类型
如果是(非CheckFormType())或(非CheckLC()),则
MsgBox(“发现错误,请检查红色突出显示的单元格”)
Application.EnableEvents=True
Application.ScreenUpdating=True
终点
如果结束
端接头
函数CheckFormType()
'如果“CS_FormType”范围内有错误的表单类型条目,则返回False,如果所有都正常,则返回True
暗i作为范围
Dim ReturnVal作为布尔值
ReturnVal=True
对于范围内的每个i(“CS_FormType”)
修剪(UCase(i.Value))
如果不是(我喜欢“[ABCDEFRS]”),那么
高亮显示(单元格(行、列))
ReturnVal=False
如果结束
下一个
CheckFormType=ReturnVal
端函数
函数CheckLC()
'如果存在错误代码,则返回False;如果一切正常,则返回True_
设置人工代码范围的格式,以根据需要添加空格并进行检查_
正确格式的人工代码(####X或##X)。省力_
以“28X”开头的代码
将代码设置为字符串
将代码长度设置为整数
暗i作为范围
作为整数的Dim j
Dim LCCell As范围
Dim LCArray()作为字符串
Dim ReturnVal作为布尔值
ReturnVal=True
对于范围内的每个i(“CS_代码”)
修剪(UCase(i.Value))
LaborCode=i.值
如果没有像“28”这样留下(劳工代码,3),那么
LaborCodeLength=Len(LaborCode)
'如果字符串LaborCode大于4,可以安全地假定它是一个范围的LaborCode 123A-123F
选择大小写代码长度
病例>4例
'如有必要,通过添加空格格式化人工代码范围字符串(即123A-123F到123A-123F)
对于j=2到第1步
如果是数字(Mid(LaborCode,j,1)),而不是数字(Mid(LaborCode,j+1,1))和非数字(Mid(LaborCode,j+2,1)=“”),则
LaborCode=左(LaborCode,j+1)和“&中(LaborCode,j+2)
ElseIf是数字的(Mid(LaborCode,j,1))和非数字的(Mid(LaborCode,j-1,1)=“”)和非数字的(Mid(LaborCode,j-1,1)),然后
LaborCode=左(LaborCode,j-1)和“&中(LaborCode,j)
如果结束
下一个
我=
Sub GenerateMajorMinor(thisWB As Workbook)
    Dim newWB As Workbook
    Dim MajMinArray() As Variant

    Set newWB = Workbooks.Add
    With newWB
        Call FormatWorkbook
        Call CreateMajMinArray(newWB, MajMinArray)
        Call PopulateItemMaster(MajMinArray)
        Call PopulateLaborLink(MajMinArray)
        Call SaveFile(newWB, thisWB)
    End With
End Sub
Sub SaveFile(newWB As Workbook, thisWB As Workbook)
    'saves new workbook into the same file path as the checksheet
    Dim i As Integer
    Dim FileSavePath As String
    Dim FamNameSave As String

    FamNameSave = Replace(FamilyName, "/", "_")

    i = 1
    FileSavePath = thisWB.Path + "/Template (Minor and Major)_" + FamNameSave + ".xls"

a:    If Dir(FileSavePath) <> "" Then
        FileSavePath = thisWB.Path + "/Template (Minor and Major)_" + FamNameSave + "(" + CStr(i) + ").xls"
        i = i + 1
        GoTo a:
    End If
    newWB.SaveAs FileSavePath, FileFormat:=56
End Sub
Sub FormatWorkbook()
    'Names and formats sheets
    Sheets(1).Name = "Item_Master"
    Sheets(2).Name = "Labor_Link"

    With Sheets(1)
        .Range("A1") = "Company_No"
        .Range("B1") = "Family_Name"
        .Range("C1") = "Form_Type"
        .Range("D1") = "Record_Status"
        .Range("E1") = "Task_Desc"
        .Range("F1") = "Task_No"
        .Range("G1") = "Task_Seq"
        .Range("H1") = "Is_Parametric"
    End With
    With Sheets(2)
        .Range("A1") = "Company_Name"
        .Range("B1") = "Family_Name"
        .Range("C1") = "Form_Type"
        .Range("D1") = "Labor_Code"
        .Range("E1") = "Print_Control"
        .Range("F1") = "Record_Status"
        .Range("G1") = "Task_No"
    End With
End Sub
Sub CreateMajMinArray(newWB As Workbook, MajMinArray As Variant)
    'creates array, removing any OPO/BTS labor codes
    With Sheets(3)
    Application.EnableEvents = True
    Application.ScreenUpdating = True
    Dim rng As Range

    Set rng = .Range(.Range("A1"), .Cells(TaskArrayRowCount, TaskArrayColCount))
    rng = TaskArray
    For i = 1 To .Range("A1").End(xlDown).Row Step 1
            If .Cells(i, 2) Like "[A-E]" Then
                .Rows(i).Delete
                i = i - 1
            End If
        Next
        For i = 1 To .Range("A1").End(xlToRight).Column Step 1
            If Left(.Cells(1, i), 3) Like "28E" Then
                .Columns(i).Delete
                i = i - 1
            End If
        Next
        ReDim MajMinArray(.Range("A1").End(xlDown).Row, .Range("A1").End(xlToRight).Column)
        MajMinArray = .Range(.Range("A1"), .Cells(.Range("A1").End(xlDown).Row, .Range("A1").End(xlToRight).Column)).Value
        .Cells.Clear
    End With
End Sub
Sub PopulateItemMaster(MajMinArray As Variant)
    With Sheets(1)
        'Populates "Item_Master" Sheet
        For i = 2 To UBound(MajMinArray) Step 1
            .Cells(i, 2) = FamilyName
            .Cells(i, 3) = MajMinArray(i, 2)
            .Cells(i, 4) = "1"
            .Cells(i, 5) = MajMinArray(i, 3)
            .Cells(i, 6) = MajMinArray(i, 1)
            .Cells(i, 7) = MajMinArray(i, 1)
        Next
    End With
End Sub
Sub PopulateLaborLink(MajMinArray As Variant)
    Dim i As Integer
    Dim LaborCode As String
    Dim RowCount As Long
    Dim LCArray() As String
    Dim LastLetter As String
    Dim LastFormType As String

    'Initializes RowCount and PrintControl
    RowCount = 2
    PrintControl = 10

    With Sheets(2)
        For i = 4 To UBound(MajMinArray, 2) Step 1
            LaborCode = Trim(MajMinArray(1, i))
    'If Labor Code String length is > 4, safe to assume that it is a range of labor codes
            Select Case Len(LaborCode)
            Case Is > 4
                LCArray = Split(LaborCode, " ")
        'checks to see if LCArray(0) and LCArray(2) has values
        If LCArray(0) = "" Or LCArray(2) = "" Then
                    MsgBox ("Error with Labor Code range. Please check and re-run")
                    Application.EnableEvents = True
                    Application.ScreenUpdating = True
                    End
                End If

                LastLetter = Chr(Asc(Right$(LCArray(2), 1)) + 1)
                LCArray(2) = Replace(LCArray(2), Right$(LCArray(2), 1), LastLetter)
                Do
                    Call PrintLaborLinkLines(MajMinArray, LCArray(0), RowCount, i)
                    LastLetter = Chr(Asc(Right$(LCArray(0), 1)) + 1)
                    LCArray(0) = Replace(LCArray(0), Right$(LCArray(0), 1), LastLetter)
                Loop Until LCArray(0) = LCArray(2)
                Erase LCArray()
            Case Is <= 4
                Call PrintLaborLinkLines(MajMinArray, LaborCode, RowCount, i)
            End Select
        Next
    End With
End Sub
Sub PrintLaborLinkLines(MajMinArray As Variant, LaborCode As String, RowCount As Long, i As Integer)
    Dim PrintControl As Long

    PrintControl = 10
    With Sheets(2)
        For x = 2 To UBound(MajMinArray) Step 1
            If UCase(MajMinArray(x, i)) = "Y" Then
                If LastFormType <> MajMinArray(x, 2) Then
                    PrintControl = 10
                End If
                .Cells(RowCount, 2) = FamilyName
                .Cells(RowCount, 3) = MajMinArray(x, 2)
                .Cells(RowCount, 4) = LaborCode
                .Cells(RowCount, 5) = PrintControl
                .Cells(RowCount, 6) = "1"
                .Cells(RowCount, 7) = MajMinArray(x, 1)
                RowCount = RowCount + 1
                PrintControl = PrintControl + 10
                LastFormType = MajMinArray(x, 2)
            End If
        Next
    End With
End Sub