【问题标题】:Search for column header, copy column and paste to master workbook搜索列标题、复制列并粘贴到主工作簿
【发布时间】:2015-06-02 15:31:11
【问题描述】:

如何复制具有这些列标题名称“TOOL CUTTER”和“HOLDER”的列(仅数据)并将它们粘贴(作为附加在每个列中,每个列具有相同的列标题名称)到另一个VBA 代码(工作表模块)所在的工作簿工作表。谢谢。 列标题 HOLDER 出现在 F10 中(最好写为 (10, 6),而 TOOL CUTTER 在 G10 (10, 11) 中,但最好让它搜索标题名称并打印该列中的任何内容,直到它完全为空(可能会出现空格)。 非常感谢任何帮助!

工作代码:循环打开文件夹中的文件 - 打开文件,将文件名打印到 Masterfile 表,将项目 J1 从文件打印到 Masterfile 表,关闭文件,打开文件夹中的下一个文件,直到所有文件都循环通过。

Option Explicit

Sub LoopThroughDirectory()

    Dim objFSO As Object
    Dim objFolder As Object
    Dim objFile As Object
    Dim MyFolder As String
    Dim Sht As Worksheet, ws As Worksheet
    Dim WB As Workbook
    Dim i As Integer
    Dim LastRow As Integer, erow As Integer
    Dim Height As Integer

    Application.ScreenUpdating = False

    MyFolder = "C:\Users\trembos\Documents\TDS\progress\"

    Set Sht = Workbooks("masterfile.xlsm").Sheets("Sheet1")

    'create an instance of the FileSystemObject
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    'get the folder object
    Set objFolder = objFSO.GetFolder(MyFolder)
    i = 1
    'loop through directory file and print names
    For Each objFile In objFolder.Files
        If LCase(Right(objFile.Name, 3)) = "xls" Or LCase(Left(Right(objFile.Name, 4), 3)) = "xls" Then
            'print file name

            Workbooks.Open Filename:=MyFolder & objFile.Name
            Set WB = ActiveWorkbook

            With WB
                For Each ws In .Worksheets
                    Sht.Cells(i + 1, 1) = objFile.Name
                    With ws
                        .Range("J1").Copy Sht.Cells(i + 1, 4)
                    End With
                    i = i + 1
                Next ws
                .Close SaveChanges:=False
            End With
        End If
    Next objFile
    Application.ScreenUpdating = True
End Sub

我正在尝试打印 HOLDER 和 TOOL CUTTER 列中的值的代码(返回错误 Tool variable is not defined in line For Each Tool In TOOLList in the block that start with the comment 'paste the TOOL list found back到这张纸:

Option Explicit

Sub LoopThroughDirectory()

    Dim objFSO As Object
    Dim objFolder As Object
    Dim objFile As Object
    Dim MyFolder As String
    Dim StartSht As Worksheet, ws As Worksheet
    Dim WB As Workbook
    Dim i As Integer
    Dim LastRow As Integer, erow As Integer
    Dim Height As Integer

    'Application.ScreenUpdating = False

    MyFolder = "C:\Users\trembos\Documents\TDS\progress\"

    Set StartSht = ActiveSheet

    'create an instance of the FileSystemObject
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    'get the folder object
    Set objFolder = objFSO.GetFolder(MyFolder)
    i = 2

    'loop through directory file and print names
    For Each objFile In objFolder.Files
        If LCase(Right(objFile.Name, 3)) = "xls" Or LCase(Left(Right(objFile.Name, 4), 3)) = "xls" Then
            'print file name
            StartSht.Cells(i, 1) = objFile.Name
            Dim NewWb As Workbook
            Set NewWb = Workbooks.Open(Filename:=MyFolder & objFile.Name)

            'print TDS values
            With WB
                For Each ws In .Worksheets
                    StartSht.Cells(i + 1, 1) = objFile.Name
                    With ws
                        .Range("J1").Copy StartSht.Cells(i + 1, 4)
                    End With
                    i = i + 1
                Next ws
                .Close SaveChanges:=False
            End With
        End If

        'print CUTTING TOOL and HOLDER lists
        Dim k As Long
        Dim width As Long
        Dim TOOLList As Object
        Dim count As Long
        Set TOOLList = CreateObject("Scripting.Dictionary")
        Dim ToolRow As Integer 'set as As Long if more than 32767 rows

        ' search for all on other sheets
        ' Assuming header means Row 1
        If objFile.Name <> "masterfile.xls" Then 'skip any processing on "Masterfile.xls"
            For Each ws In NewWb.Worksheets   'assuming we want to look through the new workbook
                With ws
                    width = .Cells(10, .Columns.count).End(xlToLeft).Column
                    For k = 1 To width
                        If Trim(.Cells(10, k).Value) = "CUTTING TOOL" Then
                            Height = .Cells(.Rows.count, k).End(xlUp).Row
                            If Height > 1 Then
                                For ToolRow = 2 To Height
                                    If Not TOOLList.exists(.Cells(ToolRow, k).Value) Then
                                        TOOLList.Add .Cells(ToolRow, k).Value, ""
                                    End If
                                Next ToolRow
                            End If
                        End If
                    Next
                End With
            Next
        End If

        ' paste the TOOL list found back to this sheet
        With StartSht
            width = .Cells(10, .Columns.count).End(xlToLeft).Column
            For k = 1 To width
                If Trim(.Cells(10, k).Value) = "CUTTING TOOL" Then
                    Height = .Cells(.Rows.count, k).End(xlUp).Row
                    count = 0
                    For Each Tool In TOOLList
                        count = count + 1
                        .Cells(Height + count, k).Value = Tool
                    Next
                End If
            Next
        End With
        'close current file, do not save changes
        NewWb.Close SaveChanges:=False
        i = i + 1
    'move to next file
    Next objFile

    'Application.ScreenUpdating = True

End Sub

【问题讨论】:

  • 工作簿是否包含名为“masterfile.xlsm”的代码?从您的代码中弄清楚有点困难。
  • @TimWilliams 是的,抱歉,这很难解释。随意问很多问题!是的,包含代码的工作簿称为“masterfile.xlsm”。我正在尝试从位于文件夹 MyFolder = "C:\Users\trembos\Documents\TDS\progress\" 中的文件中将信息写入该“masterfile.xlsm”
  • 您正在使用选项显式,我没有看到 Tool 的暗线。这就是为什么您收到未定义错误的原因。
  • 是的,我只是不知道如何定义工具。有人建议我将其定义为一个项目,但我不确定如何去做。此外,一旦我定义了Dim Tool As Object,我的代码前面就会出现错误,For Each ws In .Worksheets 行返回一个自动化错误
  • 试试Dim Tool As Variant。有关变体的更多信息:msdn.microsoft.com/en-us/library/office/gg251448.aspx

标签: vba excel copy-paste


【解决方案1】:

将一些不同的任务重构为单独的函数可以使您的代码更简洁,更易于遵循。

已编译但未经测试:

Option Explicit

Sub LoopThroughDirectory()

    Const SRC_FOLDER As String = "C:\Users\trembos\Documents\TDS\progress\"
    Const ROW_HEADER As Long = 10

    Dim f As String
    Dim StartSht As Worksheet, ws As Worksheet
    Dim WB As Workbook
    Dim i As Integer
    Dim dict As Object
    Dim hc As Range, hc2 As Range, d As Range

    Set StartSht = ActiveSheet

    i = 3
    f = Dir(SRC_FOLDER & "*.xls*", vbNormal) 'get first file name

    'find the header on the master sheet
    Set hc2 = HeaderCell(StartSht.Cells(ROW_HEADER, 1), "CUTTING TOOL")
    If hc2 Is Nothing Then
        MsgBox "No header found on master sheet!"
        Exit Sub
    End If

    'loop through directory file and print names
    Do While Len(f) > 0

        If f <> ThisWorkbook.Name Then

            Set WB = Workbooks.Open(SRC_FOLDER & f)

            For Each ws In WB.Worksheets
                StartSht.Cells(i, 1) = f
                ws.Range("J1").Copy StartSht.Cells(i, 4)
                i = i + 1
                'find the header on the source sheet
                Set hc = HeaderCell(ws.Cells(ROW_HEADER, 1), "CUTTING TOOL")
                If Not hc Is Nothing Then

                    Set dict = GetUniques(hc.Offset(1, 0))
                    If dict.count > 0 Then
                        Set d = StartSht.Cells(Rows.count, hc2.Column).End(xlUp).Offset(1, 0)
                        'add the values to the master list
                        d.Resize(dict.count, 1).Value = Application.Transpose(dict.keys)
                    End If
                Else
                    'header not found on source worksheet
                End If
            Next ws
            WB.Close savechanges:=False

        End If 'not the master file
        f = Dir() 'next file
    Loop
End Sub

'get all unique column values starting at cell c 
Function GetUniques(ch As Range) As Object
    Dim dict As Object, rng As Range, c As Range, v
    Set dict = CreateObject("scripting.dictionary")
    For Each c In ch.Parent.Range(ch, ch.Parent.Cells(Rows.count, ch.Column).End(xlUp)).Cells
        v = Trim(c.Value)
        If Len(v) > 0 And Not dict.exists(v) Then
            dict.Add v, ""
        End If
    Next c
    Set GetUniques = dict
End Function

'find a header on a row: returns Nothing if not found
Function HeaderCell(rng As Range, sHeader As String) As Range
    Dim rv As Range, c As Range
    For Each c In rng.Parent.Range(rng, rng.Parent.Cells(rng.Row, Columns.count).End(xlToLeft)).Cells
        If Trim(c.Value) = sHeader Then
            Set rv = c
            Exit For
        End If
    Next c
    Set HeaderCell = rv
End Function

【讨论】:

  • 不确定您是否希望我将其添加到我的代码中或仅使用此..但仅使用此,不会出现错误,但不会发生任何事情。也不知道为什么它在源工作表上寻找标题。我的想法是让源工作表“masterfile”打开一个文件,从文件中复制“CUTTING TOOL”并将其粘贴到“masterfile”中,然后继续遍历目录文件夹并对后续文件执行相同操作,直到没有留下。
  • 我的代码是独立的:不是你的。 “没有任何事情发生”是什么意思?没有文件被打开?我的理解是 - (1) 打开文件夹中的每个文件 not 包含代码的文件 (2) 循环遍历“源”文件中的每个工作表,记录 J1 中的文件名和值(3)从每个工作表中复制标题“切割工具”下的唯一值,并将它们附加到StartSht上具有相同标题的列表中
  • 是的,没有打开文件,也没有打印到主文件。 (1) 正确,但包含代码的文件不在该文件夹中,因此无需担心打开包含代码的文件 (2) 是的,循环遍历源文件中的每个工作表 (c:\ etc) (3) 是的,将它们放在 StartSht 上相同标题下的列表中,它是主文件,带有代码的文件。 @蒂姆威廉姆斯
  • Dir(SRC_FOLDER &amp; "*.xls*", vbNormal) 在循环中应该返回所有 Excel 文件(xls、xlsx、xlsm 等),所以我不确定你的情况。您将不得不进行一些调试并弄清楚这一点。
  • 我再次尝试了您的代码,但仍然没有任何内容输出到工作表。它似乎一直运行到第 25 行中的第一个 End If,然后向下移动到 Function HeaderCell 并重复。当我尝试使用 If hc2 Is Nothing Then 注释掉 If 语句时,它会运行 Do While 循环和 Function HeaderCell 几次,但随后在第 44 行报告,Set d = StartSht.Cells... 对象变量或 With 块变量未设置@Tim Williams
【解决方案2】:

值“TOOL CUTTER”和“HOLDER”是否总是在第 10 行?这些列中是否总是存在值?是否需要在列中允许除空白值以外的例外情况?

与此同时,您可以尝试以下几点:

Sub macro1()

    Dim Sht As Worksheet
    Dim LR As Integer, FR As Integer, ToolCol As Integer

    Set Sht = ActiveSheet

    With Sht 'Find column with TOOL CUTTER:
        ToolCol = Application.WorksheetFunction.Match("TOOL CUTTER", .Range("10:10"), 0)
        LR = .Cells(.Rows.Count, ToolCol).End(xlUp).Row 'Find last row with data in TOOL CUTTER column:
        .Range(.Cells(11, ToolCol), .Cells(LR, ToolCol)).Copy
    End With

End Sub

【讨论】:

  • 绝大多数时间它们在第 10 行。我正在搜索的任何文件,如果值不在第 10 行,则文件在需要更新。但是查找这些值的系统可能会改变,所以如果我可以按名称而不是位置来查找它们会更好
  • 当我尝试这个时,它在 ToolCol = Application.WorksheetFunction.Match("TOOL CUTTER", .Range("10:10"), 0) 行上给了我一个错误,说 Unable to get the Match property of the WorksheetFunction class
  • 如果匹配没有找到搜索词,这将出错。您可以使用:On Error GoTo MatchError 进行陷阱,或者如果发生错误,您可以使用If Not IsError Application.worksheetfunction... Then 跳过。如果您不知道值在哪一行或哪一列,您可能必须使用Find。编辑 - 我刚刚看到 Tim Williams 使用函数的解决方案 - 更好更全面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-21
相关资源
最近更新 更多