지식iN에 올라온 질문에 답을 달았다가, 결재란이나 평가표에 도장을 찍는 용도로 두고두고 쓸 만해서 정리해 둡니다. 셀에 글자 하나를 입력하면 그에 맞는 도장 이미지가 정해진 칸에 알아서 들어가는 구조입니다. 결재 서류 양식이나 평가 등급표처럼 매번 같은 이미지를 정해진 위치에 붙여야 하는 작업이라면 그대로 응용할 수 있어요.

준비: 도장 도형에 이름 붙이기

먼저 도장으로 쓸 도형(또는 그림)을 별도 시트에 모아 두고, 각각 이름을 "수", "우", "미", "양", "가"로 바꿔 둡니다. 도형을 선택한 상태에서 수식 입력줄 왼쪽의 이름 상자에 직접 입력하고 Enter를 치면 이름이 바뀝니다. 코드는 이 이름으로 도형을 찾기 때문에 이름이 정확히 일치해야 합니다.

광고

도형 이름을 수, 우, 미, 양, 가로 지정해 둔 도장 시트

그다음 B2 셀에 "수"~"가" 중 하나를 넣고 Enter를 치면, 그 등급에 해당하는 칸(D2~H2)에 도장이 붙습니다. 이미 붙어 있는 도장은 다시 붙지 않고, 다섯 글자 말고 다른 값을 넣으면 아무 일도 하지 않고 끝납니다.

B2 셀 입력에 따라 해당 칸에 도장 이미지가 삽입된 결과

코드

도장을 붙일 시트의 시트 모듈(VBE에서 해당 시트를 더블클릭해서 열리는 창)에 넣어야 합니다. 일반 모듈에 넣으면 Worksheet_Change 이벤트가 걸리지 않아요. 도장이 모여 있는 시트는 코드에서 Sheet2로 지정돼 있는데, 이건 시트 탭 이름이 아니라 VBE 프로젝트 창에 보이는 코드 이름입니다.

Option Explicit

'// 현재 시트의 셀값이 변경되면 실행되는 프로시저
Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Address = Me.[B2].Address Then    '// 셀값이 변경된 셀이 B2셀이면
        AppSetting False    '// 프로시저 값 False 호출
        Dim S As Shape, i As Integer    '// 앞으로 사용할 변수 선언

        '// 현재 시트에 해당 도형이 있으면 종료(중복 삽입 방지)
        Set S = shp(Me, Target): If Not S Is Nothing Then GoTo ErrPass

        '// 도형이 있는 시트에서 해당하는 도형이 없으면 종료
        Set S = shp(Sheet2, Target): If S Is Nothing Then GoTo ErrPass

        '// 가져올 도형 카피
        S.CopyPicture

        '// 입력한 값에 해당하는 위치값을 반환
        i = Application.WorksheetFunction.Match(Target, Array("수", "우", "미", "양", "가"), 0)

        '// 찾은 셀에 복사한 도형을 붙여넣음
        Me.Paste Destination:=[C2].Offset(, i)

        '// 붙여넣은 도형에 대해서
        With Selection
            '// Top 설정(셀의 세로 가운데)
            .Top = .TopLeftCell.Top + (.TopLeftCell.Height - .Height) / 2
            '// 왼쪽 설정(셀에 가로 가운데)
            .Left = .TopLeftCell.Left + (.TopLeftCell.Width - .Width) / 2

            '// 도형의 이름을 변경(추후 중복 삽입 방지)
            .Name = Target
        End With
ErrPass:
        '// 입력받은 셀로 복귀
        Target.Activate

        '// 화면의 변화와 이벤트 활성
        AppSetting True

    End If
End Sub

'// 지정한 시트에 지정한 이름의 도형을 반환하는 함수
Private Function shp(ByVal S As Worksheet, ByVal Name As String) As Shape
    On Error Resume Next
    Set shp = S.Shapes(Name)
End Function

'// 스크린 변화와 이벤트 비활성/활성 프로시저
Private Sub AppSetting(ByVal value As Boolean)
    Application.ScreenUpdating = value  '// 화면의 변화를 value 값으로
    Application.EnableEvents = value    '// 이벤트 사용여부 활성/비활성
End Sub

어떻게 중복을 막고 위치를 맞추나

중복 방지는 도형 이름으로 합니다. 붙여 넣은 도장의 이름을 입력값("수" 등)으로 바꿔 두니까, 다음에 같은 값을 넣으면 shp(Me, Target)이 현재 시트에서 그 이름의 도형을 찾아내고 바로 빠져나갑니다. shp 함수는 On Error Resume Next로 감싸서, 그 이름의 도형이 없을 때 오류 대신 Nothing을 돌려주게 만든 작은 도우미예요. 같은 함수로 도장 시트(Sheet2)에도 그 이름이 있는지 확인하니, "수"~"가" 외의 글자를 넣으면 여기서 걸러집니다.

붙일 칸은 Match로 정합니다. 배열 안에서 입력값의 순번(1~5)을 구한 뒤 [C2].Offset(, i)로 C2에서 그만큼 오른쪽으로 옮기니 "수"는 D2, "가"는 H2가 됩니다. 결재란 위치가 다르면 기준 셀 [C2]와 배열 순서만 바꾸면 되고, "담당/과장/부장"처럼 다른 이름을 쓰고 싶으면 배열과 도형 이름을 함께 바꿔 주면 됩니다.

붙여 넣은 직후의 도형은 Selection으로 잡히고, TopLeftCell(도형 왼쪽 위가 걸친 셀)을 기준으로 가로·세로 가운데로 옮겨 줍니다. 칸보다 도장이 크면 가운데 정렬이 어긋나 보이니, 도장 시트의 도형 크기를 칸보다 약간 작게 맞춰 두는 게 좋습니다.

이벤트를 끄고 켜는 부분은 빼먹지 말 것

AppSetting False로 EnableEvents를 끄는 건 꼭 필요합니다. 붙여넣기나 이름 변경 중에 다시 이벤트가 발생해 같은 프로시저가 겹쳐 도는 걸 막기 위해서예요. 대신 중간에 처리되지 않은 오류가 나서 AppSetting True까지 못 가면, 그 뒤로는 이벤트가 꺼진 채로 남아 셀을 입력해도 아무 반응이 없습니다. 이렇게 먹통이 되면 직접 실행 창에서 Application.EnableEvents = True를 한 번 실행해 주면 살아납니다. 손에 익으면 On Error GoTo ErrPass를 앞쪽에 하나 넣어 두는 것도 방법입니다.

도장을 지우고 싶을 때는 해당 도형을 선택해서 Delete로 지우면 됩니다. 이름이 사라지니 다시 입력하면 새로 붙습니다.