使用VBA缩进父子列 [英] Using VBA to indent parent child columns

查看:52
本文介绍了使用VBA缩进父子列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有下表,需要缩进父母关系的帮助.根节点从0开始,可以像子关系一样遍历1000多个级别.

I have the table below and need help indenting parent child relationships. The root node starts at 0 and can traverse 1000+ levels deep as can the child relationships.

我如何在VBA中实现这一目标?

How do i achieve this in VBA?

CPackName      CPackID      PPackID      PName      ParentID      PDATA 
Artifacts      1            1            AC         0             297
Template       1            1            AC         0             281
WA             1            1            AC         0             361
Alisha         361          361          WA         1             611 
Damian         361          361          WA         1             480
ABC            297          297          Artifacts  1             
DEF            297          297          Artifacts  1

我想在下面的列中显示.

I would like to show this in columns as below.

推荐答案

以下Excel-VBA模块对我有用.

The following Excel-VBA module works for me.

Option Explicit

Type Tree_Node          ' note: and IDX of zero means that it does not exist.
    Idx As Long         'The array index of the original source record
    ParentIdx As Long   'The array index of the parent of this node
    Depth As Long       'The number of parent nodes above this node
    OutRow As Long      'The row offset this node should appear at
    Flink As Long       'next sibling of this node
    ChildCount As Long  'number of children found so far
    HeadIdx As Long     'First child node of this parent-node
    TailIdx As Long     'Last child node of this parent node
End Type
Private nod() As Tree_Node

Private maxDepth As Long

' Formats Record/Pack data into indented records.
'
'Parameters:
'   InputRange      - The source range that contains the record/pack data.
'                    (should NOT include the column headers)
'   FirstOutputCell - The top-left cell that the output data will be written to.
'                    All cells below or to the right of this may be overwritten.
'
Sub OutputIndentedRecords(InputRange As Range, FirstOutputCell As Range)
    ' Get all of the input data into a variant array
    Dim src As Variant
    src = InputRange
    Dim srcRows As Long
    srcRows = UBound(src, 1)
    ' source range column offsets
    Const CPackName = 1
    Const PPackID = 3
    Const PDATA = 6

    Dim PDataIdxs As New Collection 'collection to index the PDATA values
    ReDim nod(srcRows)  'array to hold the Tree Nodes representing each record

    '   make the zero entry the ultimate root, with no parent
    nod(0).ParentIdx = -1
    PDataIdxs.Add 0, "1"

    '   For each record in the source range, make a Tree_Node to represent it
    '(NOTE: This algorithm assumes that the parent always appears before its children
    '       in the source range.)
    Dim i As Long, j As Long
    For i = 1 To srcRows
        'is there a record here?
        If src(i, CPackName) <> "" Then
            ' Yes, so fill in the tree node
            With nod(i)

                .Idx = i
                ' Get the parent index
                .ParentIdx = PDataIdxs(CStr(src(i, PPackID)))
                ' add this node to the Parents child list
                With nod(.ParentIdx)
                    If .TailIdx <> 0 Then       'if theres already a child
                        nod(.TailIdx).Flink = i 'point it to us
                    Else                        'otherwise
                        .HeadIdx = i            'we are the head of the child list
                    End If
                    .TailIdx = i                'we are the new tail
                    .ChildCount = .ChildCount + 1
                End With

                ' Is it a potential Parent?
                If src(i, PDATA) <> "" Then
                    'yes, so flag it and index its PDATA value
                    PDataIdxs.Add i, CStr(src(i, PDATA))
                End If

            End With
        End If
    Next i

    ' Traverse the Tree structure, filling in Depth and Output row number
    Dim curRow As Long
    curRow = 1
    maxDepth = 0

    TraverseTreeDepthFirst 0, 1, curRow

    ' Make an output array and fill it in
    Dim out() As Variant
    ReDim out(curRow - 2, maxDepth - 2)
    For i = 1 To srcRows
        With nod(i)
            out(.OutRow - 2, .Depth - 2) = src(.Idx, CPackName)
        End With
    Next i

    'Make an output range to hold the array
    Dim wsOut As Worksheet, rngOut As Range
    Set wsOut = FirstOutputCell.Worksheet
    Set rngOut = wsOut.Range(FirstOutputCell, _
                            wsOut.Cells(FirstOutputCell.Row + curRow - 2, _
                                        FirstOutputCell.Column + maxDepth - 2))
    ' write out the output array
    rngOut = out
End Sub

' Depth-first tree traversal, filling in the node depth and row number
Sub TraverseTreeDepthFirst(ByVal cur As Long, ByVal curDepth As Long, ByRef curRow As Long)
    With nod(cur)

        ' set values of the current node
        .Depth = curDepth
        .OutRow = curRow
        curRow = curRow + 1
        If curDepth > maxDepth Then maxDepth = curDepth

        ' Traverse any children first
        If .HeadIdx > 0 Then
            TraverseTreeDepthFirst .HeadIdx, curDepth + 1, curRow
        End If

        ' Move to next sibling
        If .Flink > 0 Then
            TraverseTreeDepthFirst .Flink, curDepth, curRow
        End If
    End With

End Sub

只需调用 OutputIndentedRecords ,传入源数据范围和输出范围的第一个单元格即可.

Just call OutputIndentedRecords passing in the range of the source data and the first cell of the output range.

如果您有任何疑问,请告诉我.

Let me know if you have any questions.

以下是设置按钮以调用此子例程的方法:

Here's how to setup a button to call this subroutine:

首先,将以下VBA代码添加到主题工作表的代码模块中:

First, add the following VBA code to your subject worksheet's code module:

Sub CallOutputIndent()

    Dim src As Range
    Set src = Selection

    OutputIndentedRecords src, Worksheets("OutputWs").Cells(2, 2)

End Sub

将上面的工作表名称从"OutputWs"更改为您输出的工作表名称.还可以将(2,2)更改为该工作表上第一个输出单元格应该是的形式.

Change the Worksheet name above from "OutputWs" to whatever you output worksheet is named. also change the (2,2) to whatever the first output cell on that worksheet should be.

接下来,转到源工作表,然后从插入"菜单中添加按钮/矩形.右键单击它并选择分配宏..",然后为其分配 CallOutputIdent 宏.

Next, go to your source worksheet and from the "Insert" menu, add a button/rectangular shape. Right-click it and pick "Assign Macro..", and then assign the CallOutputIdent macro to it.

要使用它,只需选择输入范围,然后单击按钮.应该就是这样.

To use it, just select the input range and click the button. that should be it.

这篇关于使用VBA缩进父子列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆