Quantcast
Channel: t-hom’s diary
Viewing all articles
Browse latest Browse all 493

VBA 重なっているシェイプをグループ化するマクロ

$
0
0

今回の記事は重なりあうシェイプを自動判定してグループ化するマクロ。
といっても以前にクラスモジュールを使用してシェイプ同士が重なっているかどうかの判定までは作ってるので今回は手入れしてちゃんとグルーピング部分まで完成させたのでコードの紹介のみ。
thom.hateblo.jp

クラスモジュール

クラスモジュールを挿入し、オブジェクト名をShapeWrapperとしておく。
その名のとおり、Shapeを内包して今回のマクロ用に便利に扱う為のもの。

Private InnerShape As Shape

PublicPropertyGetName()AsStringName= InnerShape.NameEndPropertyPublicSub SetShape(s As Shape)Set InnerShape = s
EndSubPublicPropertyGet Top()AsSingle
    Top = InnerShape.Top
EndPropertyPublicPropertyGetLeft()AsSingleLeft= InnerShape.LeftEndPropertyPublicPropertyGet Bottom()AsSingle
    Bottom = InnerShape.Top + InnerShape.Height
EndPropertyPublicPropertyGetRight()AsSingleRight= InnerShape.Left+ InnerShape.WidthEndPropertyPublicPropertyGet Nodes(Number AsInteger)As Node
    SelectCase Number
        Case1
            Nodes.x =Me.Left
            Nodes.y =Me.Top
        Case2
            Nodes.x =Me.Right
            Nodes.y =Me.Top
        Case3
            Nodes.x =Me.Right
            Nodes.y =Me.Bottom
        Case4
            Nodes.x =Me.Left
            Nodes.y =Me.Bottom
        CaseElse
            Err.Raise1000,,"1~4を指定してください。"EndSelectEndPropertyPublicFunction IsOverlapped(SW As ShapeWrapper)AsBooleanDim i AsIntegerFor i =1To4Step1
        IsOverlapped = _(SW.Nodes(i).x >Me.LeftAnd _
            SW.Nodes(i).x <Me.RightAnd _
            SW.Nodes(i).y >Me.Top And _
            SW.Nodes(i).y <Me.Bottom) _Or _(Me.Nodes(i).x > SW.LeftAnd _Me.Nodes(i).x < SW.RightAnd _Me.Nodes(i).y > SW.Top And _Me.Nodes(i).y < SW.Bottom)If IsOverlapped ThenExitFunctionNextEndFunction

肝となるのはIsOverlappedメソッド。これはShapeWrapper(つまり自己と同じ型のオブジェクト)を引数にとり、自分と重なっているかどうかを判定するメソッド。詳しくは冒頭で紹介した記事を参照。

標準モジュール

標準モジュールを挿入し、オブジェクト名を「Grouping」とする。ただまあ標準モジュールの命名は任意。

PublicType Node
    x AsSingle
    y AsSingleEndTypePrivateFunction WrappedShapes()As Collection
   'シェイプをShapeWrapperで包んでコレクションに追加Dim c AsNew Collection, s As Shape, SW1 As ShapeWrapper
    ForEach s In ActiveSheet.Shapes
        Set SW1 =New ShapeWrapper
        SW1.SetShape s
        c.Add SW1, SW1.NameNext'コレクションの各シェイプ同士の重なり判定Dim c2 As Collection: Set c2 =New Collection
    
    Dim SW2 As ShapeWrapper
    ForEach SW1 In c
        Dim arr()AsVariantReDim arr(0)
        arr(0)= SW1.Name
        c.Remove SW1.NameForEach SW2 In c
            IfNot(SW1 Is SW2)ThenIf SW1.IsOverlapped(SW2)ThenReDimPreserve arr(UBound(arr)+1)
                    arr(UBound(arr))= SW2.Name
                    c.Remove SW2.NameEndIfEndIfNext
        c2.Add arr
    NextSet WrappedShapes = c2
EndFunctionPrivateSub RecUngroupShape(sh As Shape)Dim memberShape As Shape
    If sh.Type= msoGroup ThenForEach memberShape In sh.Ungroup
            Call RecUngroupShape(memberShape)NextEndIfEndSubPublicSub GroupOverlappingShape()Dim SW()AsVariantDim c As Collection: Set c = WrappedShapes
    For i =1To c.Count
        SW = c(i)
        ActiveSheet.Shapes.Range(SW).Group
    NextEndSubPublicSub UngroupAllShapes()Dim sh As Shape
    ForEach sh In ActiveSheet.Shapes
        Call RecUngroupShape(sh)NextEndSub

色々プロシージャがあるけれどマクロとして単体実行できるのはPublicになっている最後の2つのみ。
GroupOverlappingShapeを実行すると、アクティブなシート上で重なっているシェイプがすべてグループ化される。
UngroupAllShapesを実行するとアクティブなシート上のすべてのシェイプグループが解除される。

こんな感じで、赤枠と画像の重ね合わせはグループ化しておくと便利。
f:id:t-hom:20180602120054p:plain

RecUngroupShapeとUngroupAllShapesはひとつ前の記事で紹介しており、今回の処理に必須ではないがGroupingモジュールの仲間としては相応しと思ったのでついで。

以上


Viewing all articles
Browse latest Browse all 493

Trending Articles