使用 VBA 将标签与 Excel 流程图中的箭头匹配

问题描述 投票:0回答:3

我正在 Excel 中使用 VBA 编写一个代码生成工具(不要问为什么——说来话长)。我需要能够“解析”流程图。

问题在于 Excel 允许形状包含文本,但连接器除外:线条和箭头不能包含文本。要标记箭头,只需在其顶部放置一个文本框,但该框并未以 VBA 可以轻松捕获的方式“附加”到箭头。

例如,用户可能会画这样的东西:

example flowchart: three boxes, two arrows, two more boxes as arrow labels

在我的VBA代码中,我可以使用

ActiveSheet.Shapes
发现流程图包含七个形状:有五个框(两个标签只是没有边框的框)和两个箭头。然后
Shape.TextFrame2
会告诉我每个方框内写的内容,
Shape.ConnectorFormat
会告诉我每个箭头的开头和结尾是哪个方框。

我需要的是可以推断出的代码:

  • 标签A属于从方框1到方框2的箭头
  • 标签B属于从方框1到方框3的箭头

我可以想到三种方法来做到这一点,但没有一个令人满意。

  1. 要求用户将每个标签及其相应的箭头分组。

  2. 找出每个箭头的端点坐标,然后 计算哪些箭头穿过哪些标签。

  3. 找出每个盒子的角点坐标,然后计算 哪些标签位于哪对盒子之间。

方法 1 让程序员的事情变得更容易,但对用户来说却更困难。它为用户错误带来了很大的可能性。 我不认为这是一个可接受的解决方案。

方法2相当容易实现,只是我不知道如何找出坐标!

方法3是可行的(

Shape.Left
等会给出坐标)但计算上相当混乱。它还可能存在歧义(根据放置的位置,相同的标签可能与多个箭头相关联)。

请注意,方法 2 和 3 都涉及尝试将每个标签与每个箭头进行匹配:复杂性是二次的。典型的应用程序将有 10-50 个箭头,因此这种方法是可行的,尽管有些不优雅。

有人有更好的主意吗?理想情况下,它应该不涉及坐标几何和复杂的逻辑,也不涉及要求用户改变他们绘制流程图的方式。


编辑添加:示例 2 回应 Tim Williams

flowchart with one box, two arrows, and a label whose bounding box intersects the bounding boxes of both arrows

这是一个标签,其边界框与两个箭头的边界框相交,并且其中点不在任一箭头的边界框内。从视觉上看,人们很容易看出它属于左箭头,但从编程角度来说,这很难处理。如果我能找出箭头端点的坐标,那么我就可以计算出一个箭头穿过标签的框,但另一个箭头没有穿过。 但如果我只有箭头的边界矩形,那么它就不起作用。

vba excel charts
3个回答
1
投票

有趣的问题。如果您考虑箭头覆盖的范围和文本框覆盖的范围并根据最多重叠来匹配它们会怎么样?

Sub ListShapes()

    Dim shp As Shape
    Dim shpArrow As Shape
    Dim vaArrows As Variant
    Dim i As Long
    Dim rIntersect As Range
    Dim aBestFit() As String
    Dim lMax As Long

    vaArrows = Split("Straight Arrow Connector 7,Straight Arrow Connector 9", ",")
    ReDim aBestFit(LBound(vaArrows) To UBound(vaArrows))

    For i = LBound(vaArrows) To UBound(vaArrows)
        Set shpArrow = Sheet1.Shapes(vaArrows(i))
        lMax = 0

        For Each shp In Sheet1.Shapes
            If shp.Name Like "Label*" Then
                Set rIntersect = Intersect(Sheet1.Range(shp.TopLeftCell, shp.BottomRightCell), _
                    Sheet1.Range(shpArrow.TopLeftCell, shpArrow.BottomRightCell))

                If Not rIntersect Is Nothing Then
                    If rIntersect.Count > lMax Then
                        lMax = rIntersect.Count
                        aBestFit(i) = shp.Name
                    End If
                End If
            End If
        Next shp
    Next i

    For i = LBound(vaArrows) To UBound(vaArrows)
        Debug.Print vaArrows(i), aBestFit(i)
    Next i

End Sub

我用五框二箭头设置对此进行了测试,没有什么更复杂的。 我将两个箭头放在一个数组中,但我假设您有方法来识别箭头。我还将我的不受束缚的盒子命名为“标签 x”,这样我就可以识别它们,但我再次假设你有更复杂的东西。

代码循环遍历每个箭头。在该循环内,它循环遍历每个形状。如果它是标签,那么它会计算两个范围交集内的单元格。哪个最多就存储在最适合的数组中。

如果您有一个合理的流程图语料库来测试它以了解陷阱在哪里,那就太好了。我认为这不一定比使用坐标更好,只是一种不同的方法。


1
投票

您可以按如下方式找到箭头端点的坐标。

首先,正如 Tim Williams 指出的那样,

.Left
.Top
.Width
.Height
属性描述了箭头的边界矩形。

接下来,检查 .HorizontalFlip 和 .VerticalFlip 属性。 如果两者都为 false,则箭头在其边界矩形中从左上角延伸到右下角。 也就是说,箭头的起点坐标为

(.Left,.Top)
,终点坐标为
(.Left+.Width,.Top+.Height)

如果 *.Flip 为 true,则需要适当交换坐标。 例如,如果

.HorizontalFlip
为 true 但
.VerticalFlip
为 false,则箭头从
(.Left+.Width,.Top)
(.Left,.Top+.Height)

据我所知,MSDN 上没有任何记录。 感谢 Andy Pope 在 excelforums.com 上提到这一点。

鉴于此,方法 2 似乎是最好的方法。


0
投票

只需请求 ms excel 有此选项来标记线连接器,就像它允许在自动形状上添加标签一样...

© www.soinside.com 2019 - 2024. All rights reserved.