글목록

2022년 3월 9일

PowerPoint 매크로 - 그림, 도형 정렬/배열하기 (1) - 선택순 배열

여러개의 그림이나 도형을 줄을 맞춰 배열해야하는 경우가 있습니다.

Powerpoint에서는 기본적으로 도형을 정렬하는 기능이 있어서, 상하좌우 맞춤이나 등간격 배열도 가능합니다만, 1줄 정렬인 경우에는 가능하지만 2줄 이상의 격자 배열을 하려면 반복된 작업을 해야하는 경우가 있습니다.

도형을 배열하는 기능의 매크로는 인터넷을 찾아보면 쉽게 구할 수 있습니다만, 사용자가 지정한 위치에 배열하는 기능은 잘 구하기 어렵습니다. 따라서, 아래와 같은 기능을 갖도록 매크로를 만들어보았습니다.

- 사용자가 선택한 순서대로 배열하기
- 사용자가 배열할 위치를 선택하고, 가로/세로 배열할 행렬 갯수 지정하기
- 그림간 간격을 지정하기


예를 들어, 아래의 그림과 같이, 각 그림이 무작위로 배열되어 있다면, 배열할 순서대로 클릭하여 그림을 선택합니다.


그림을 배열할 위치를 지정할 수 있도록 4각형 박스의 위치와 크기를 지정합니다. 만약 4각형 박스가 없다면 생성해주도록 합니다. 4각형 박스 내에 가로, 세로로 배열할 행/열 수와 그림 간격을 입력받습니다.


4각형 박스 안에 그림의 크기를 조절하여 배열합니다. 배열을 마치면 4각형 박스를 지웁니다. 



만약, 여러 슬라이드에 걸쳐 동일하게 배열을 하고 싶다면, 4각형 박스의 위치정보를 그대로 가져와서 다른 페이지에도 적용하도록 아래의 매크로를 수정하시면 됩니다.

아래의 매크로는 그림을 선택한 순서대로 배열합니다. 그림의 갯수가 많을 때, 마우스로 드래그해서 여러개의 그림을 선택하게 되면, 그림의 ZOrder에 따라 선택순서가 지정되기 때문에 정확한 순서대로 배열하기 위해서는 각각의 그림을 클릭해서 선택해주어야하는 문제가 있습니다.

그러나, 사용자 입장에서는 그림의 갯수가 많을 때 일일이 클릭하는 것도 귀찮은 일일 수 있습니다. ZOrder에 상관없이 현재 배열된 상태를 해석해서 가장 근접한 행/열에 배열해줄 수 있다면, 사용자 입장에서는 훨씬 편리할 수 있습니다. 그러나, 1차원이 배열이라면 그림의 순서를 쉽게 지정해줄 수 있지만, 2차원으로 무작위 배열된 개체를 가장 근접한 행/열로 지정하는 것은 많은 수학적 해석이 필요합니다. 차후에 시간이 되면 2차원 배열된 개체를 현재의 배열을 최대한 유지하면서 행/열로 배열하는 매크로를 올리도록 하겠습니다.


'-------------------------------------------------
  '그림을 배열할 4각형 박스를 할당하도록 Shape 변수를 선언해둡니다.
Public AlignBox As Shape
'-------------------------------------------------
Function Check_ShapeExist(iSlide As Slide, iSh As Shape) As Boolean
  '현재 슬라이드에 도형이 있는지, 혹은 삭제되었는지 확인하는 함수로, 4각형 박스가 있는지 체크하기 위한 함수입니다.
  '도형의 이름과 ID를 체크해서 오류가 난다면 도형이 없다고 판단합니다.
  On Error GoTo ErrorHandler
  Dim tStr As String, tID
  tStr = iSlide.Shapes(iSh.Name).Name
  tID = iSlide.Shapes(iSh.Name).Id
  Check_ShapeExist = True
  Exit Function
ErrorHandler:
  Check_ShapeExist = False
End Function
'-------------------------------------------------
Function ControlAlignBox(Optional iNew As Boolean = True)
  '4각형 박스를 생성하도록 합니다. 4각형 박스가 없다면 새로 생성하고, 있다면 생성하지 않습니다. 반대로, iNew = False로 입력되면 4각형 박스를 지웁니다.
  Dim tCheck As Boolean
  tCheck = Check_ShapeExist(ActiveSlide, AlignBox)
  If iNew And Not tCheck Then
    Set AlignBox = ActiveSlide.Shapes.AddShape(msoShapeRectangle, ActivePresentation.PageSetup.SlideWidth * 0.05, ActivePresentation.PageSetup.SlideHeight * 0.05, ActivePresentation.PageSetup.SlideWidth * 0.9, ActivePresentation.PageSetup.SlideHeight * 0.9)
    With AlignBox
      .Line.Visible = msoTrue
      .Line.DashStyle = msoLineDash
      .Line.Weight = 1.5
      .Line.ForeColor.RGB = RGB(255, 0, 0)
      .Fill.Visible = msoFalse
    End With
  ElseIf (Not iNew) And tCheck Then
    AlignBox.Delete
  End If
End Function
'-------------------------------------------------
Sub AlignShapes_Selection()
  '도형을 클릭하여 선택한 상태에서 원하는 위치에 도형을 배열하도록 합니다.
  On Error GoTo ErrorHandler
  Dim tSlide As Slide, tSR As ShapeRange, tSh() As Shape
  Dim i As Long, j As Long, k As Long, n As Long
  Dim tStr As String, tNW As Long, tNH As Long, tLeft As Single, tTop As Single
  Dim tCellW As Single, tCellH As Single, tShW As Single, tShH As Single, tMW As Single, tMH As Single
  
  Set tSlide = ActiveSlide

  '도형을 배열할 4각형 박스가 없다면, 4각형 박스를 만들고 매크로를 종료합니다. 4각형 박스는 원하는 위치로 이동하거나 크기를 변경합니다.
  If Not Check_ShapeExist(tSlide, AlignBox) Then
    MsgBox "그림 배열을 위한 도구상자가 없습니다. 생성된 도구상자를 이용하여 그림을 배열할 위치를 지정하세요.", vbInformation, "작업 오류"
    ControlAlignBox True
    Exit Sub
  End If

  '현재 선택된 그림에 4각형 박스가 포함되어 있다면, 박스를 제외한 나머지 도형만 정렬할 대상으로 지정합니다. 만약, 선택된 도형이 없다면 매크로를 종료합니다.
  Set tSR = SelectedShapeRange(True)
  n = 0
  For i = 1 To tSR.Count
    If tSR(i).Name <> AlignBox.Name And tSR(i).Id <> AlignBox.Id Then
      n = n + 1
      ReDim Preserve tSh(1 To n)
      Set tSh(n) = tSR(i)
    End If
  Next
  If n = 0 Then Exit Sub
  
  '4각형 박스 내에 가로, 세로 배열 갯수, 간격을 입력받습니다.
  tNW = -Int(-Sqr(n))
  tStr = InputBox("가로로 배열할 갯수를 입력하세요.", "가로 배열", tNW)
  tNW = Val(tStr)
  If tNW <= 0 Then Exit Sub
  
  tNH = -Int(-n / tNW)
  tStr = InputBox("세로로 배열할 갯수를 입력하세요.", "세로 배열", tNH)
  tNH = Val(tStr)
  If tNH < 0 Then Exit Sub
  
  tStr = InputBox("가로 방향 그림 간격을 입력하세요. (% 단위)", "가로 간격", 0)
  If StrPtr(tStr) = 0 Then Exit Sub
  tMW = Val(tStr)
  
  tStr = InputBox("세로 방향 그림 간격을 입력하세요. (% 단위)", "세로 간격", 0)
  If StrPtr(tStr) = 0 Then Exit Sub
  tMH = Val(tStr)
  
  '4각형 박스의 위치, 크기 정보로부터 각 그림의 크기를 지정할 수 있도록 크기, 간격 값을 계산해둡니다.
  With AlignBox
    tLeft = .Left
    tTop = .Top
    tCellW = .Width / tNW
    tCellH = .Height / tNH
    tMW = tCellW * tMW / 100
    tMH = tCellH * tMH / 100
    tShW = tCellW - tMW * 2
    tShH = tCellH - tMH * 2
  End With
  
  '그림의 크기를 변경한 후, 4각형의 각 위치에 그림을 배열합니다. 만약, 그림의 가로/세로 비율을 유지하고자 한다면, .LockAspectRatio = msoTrue로 두고, 폭이나 높이만 변경합니다.
  j = -1: k = -1
  For i = 1 To n
    j = (j + 1) Mod tNW
    If j = 0 Then k = (k + 1) Mod tNH
    With tSh(i)
      .LockAspectRatio = msoFalse
      .Width = tShW
      .Height = tShH
      .Left = tLeft + j * tCellW + tMW
      .Top = tTop + k * tCellH + tMH
    End With
  Next
ErrorHandler:
  Erase tSh
End Sub



많이 본 글 :