Shape 개체

엑셀에서 진짜 ‘아날로그 시계’를 만드는 방법 (VBA 시계 만들기)

노만e 2025. 9. 13. 15:58

 

엑셀로 시계를 만든다?
놀랍지만 실제로 작동하는 아날로그 시계가 가능합니다!
오늘은 VBA(매크로)를 활용해, 엑셀 워크시트 위에 실시간으로 움직이는 시계를 구현하는 방법을 소개할게요.


💡 어떤 시계인가요?

이 매크로는 엑셀 시트에 다음과 같은 시계를 만들어줍니다:

  • 🕒 12시 방향 숫자와 눈금이 있는 원형 시계
  • 시침/분침/초침이 실시간으로 갱신
  • 🟢 매 1초마다 자동 업데이트 (Application.OnTime 사용)
  • ⚙ 필요 시 시계 정지 버튼도 제공 (StopClock)

📌 핵심 구성요소

구성요소설명
DrawClockFace 시계 외곽, 숫자, 눈금, 중심 점 생성
UpdateClock 현재 시간을 읽어 바늘 각도 계산 후 그리기
StartClock 시계 시작 (초기화 및 타이머 등록)
StopClock 시계 중지 (타이머 해제)

📽 VBA 코드

Option Explicit

' ===== 설정값 =====
Private nextTime As Date
Private Const SHT As String = "Clock"
Private Const CX As Single = 200    ' 중심 X
Private Const CY As Single = 200    ' 중심 Y
Private Const R  As Single = 150    ' 반지름
Private Const PI As Double = 3.14159265358979

' ===== 공개 진입점 =====
Public Sub StartClock()
    Dim ws As Worksheet: Set ws = EnsureSheet(SHT)
    DrawClockFace ws
    UpdateClock
End Sub

Public Sub StopClock()
    On Error Resume Next
    Application.OnTime earliesttime:=nextTime, procedure:="UpdateClock", schedule:=False
    On Error GoTo 0
End Sub

' ===== 유틸 =====
Private Function EnsureSheet(ByVal name As String) As Worksheet
    On Error Resume Next
    Set EnsureSheet = ThisWorkbook.Worksheets(name)
    On Error GoTo 0
    If EnsureSheet Is Nothing Then
        Set EnsureSheet = ThisWorkbook.Worksheets.Add
        EnsureSheet.name = name
    End If
End Function

Private Sub DeleteByPrefix(ws As Worksheet, ByVal prefix As String)
    Dim i As Long
    For i = ws.Shapes.Count To 1 Step -1
        If Left$(ws.Shapes(i).name, Len(prefix)) = prefix Then
            ws.Shapes(i).Delete
        End If
    Next i
End Sub

Private Sub DeleteIfExists(ws As Worksheet, ByVal nm As String)
    On Error Resume Next
    ws.Shapes(nm).Delete
    On Error GoTo 0
End Sub

' ===== 시계판 그리기 =====
Private Sub DrawClockFace(ws As Worksheet)
    Dim i As Long, ang As Double
    Dim x1 As Single, y1 As Single, x2 As Single, y2 As Single

    Application.ScreenUpdating = False

    ' 이전 시계판 지우기(바늘 포함 모든 시계 객체)
    DeleteByPrefix ws, "CLK_"

    ' 외곽 원판
    With ws.Shapes.AddShape(msoShapeOval, CX - R, CY - R, 2 * R, 2 * R)
        .name = "CLK_Dial"
        .Fill.ForeColor.RGB = RGB(255, 255, 255)
        .Line.Weight = 2
    End With

    ' 12개 눈금 + 숫자
    For i = 1 To 12
        ang = (i / 12) * 2 * PI - PI / 2

        ' 굵은 눈금
        x1 = CX + (R - 12) * Cos(ang): y1 = CY + (R - 12) * Sin(ang)
        x2 = CX + (R - 2) * Cos(ang): y2 = CY + (R - 2) * Sin(ang)
        With ws.Shapes.AddLine(x1, y1, x2, y2)
            .name = "CLK_Tick_" & i
            .Line.Weight = 2
        End With

        ' 숫자
        With ws.Shapes.AddTextbox(msoTextOrientationHorizontal, _
                CX + (R - 28) * Cos(ang) - 10, _
                CY + (R - 28) * Sin(ang) - 10, 30, 20)
            .name = "CLK_Num_" & i
            .TextFrame.Characters.Text = CStr(i)
            .TextFrame.HorizontalAlignment = xlHAlignCenter
            .TextFrame.VerticalAlignment = xlVAlignCenter
            .Line.Visible = msoFalse
        End With
    Next

    ' 중심 캡
    With ws.Shapes.AddShape(msoShapeOval, CX - 4, CY - 4, 8, 8)
        .name = "CLK_Center"
        .Fill.ForeColor.RGB = RGB(0, 0, 0)
        .Line.Visible = msoFalse
    End With
    
    Application.ScreenUpdating = True
End Sub

' ===== 바늘 갱신 =====
Public Sub UpdateClock()
    Dim ws As Worksheet: Set ws = EnsureSheet(SHT)
    Dim h As Long, m As Long, s As Long
    Dim ang As Double
    Dim hLen As Single, mLen As Single, sLen As Single

    h = Hour(Now): m = Minute(Now): s = Second(Now)

    hLen = R * 0.5
    mLen = R * 0.7
    sLen = R * 0.85

    Application.ScreenUpdating = False

    ' 이전 바늘 안전 삭제 (개별 삭제 → 1004 방지)
    DeleteIfExists ws, "CLK_Hour"
    DeleteIfExists ws, "CLK_Minute"
    DeleteIfExists ws, "CLK_Second"

    ' 시침(분/초 반영)
    ang = ((h Mod 12) + m / 60# + s / 3600#) * (2 * PI / 12#) - PI / 2
    With ws.Shapes.AddLine(CX, CY, CX + hLen * Cos(ang), CY + hLen * Sin(ang))
        .name = "CLK_Hour"
        .Line.Weight = 4
    End With

    ' 분침(초 반영)
    ang = (m + s / 60#) * (2 * PI / 60#) - PI / 2
    With ws.Shapes.AddLine(CX, CY, CX + mLen * Cos(ang), CY + mLen * Sin(ang))
        .name = "CLK_Minute"
        .Line.Weight = 3
    End With

    ' 초침
    ang = s * (2 * PI / 60#) - PI / 2
    With ws.Shapes.AddLine(CX, CY, CX + sLen * Cos(ang), CY + sLen * Sin(ang))
        .name = "CLK_Second"
        .Line.Weight = 1
        .Line.ForeColor.RGB = RGB(200, 0, 0)
    End With

    Application.ScreenUpdating = True

    ' 1초 후 예약
    nextTime = Now + TimeSerial(0, 0, 1)
    Application.OnTime earliesttime:=nextTime, procedure:="UpdateClock"
End Sub

 

✍ 사용 방법

1️⃣ VBA 코드 붙여넣기

  • Alt + F11 → VBA 편집기 열기
  • 새 모듈(Module) 생성 → 코드 전체 복사 & 붙여넣기

2️⃣ 시계 시작

 
StartClock
  • 즉시 새로운 시트(Clock)에 시계가 생성됩니다.
  • 초침이 1초마다 움직입니다.

3️⃣ 시계 정지

 
StopClock
  • 타이머를 해제하여 시계 작동을 멈춥니다.

⚙ 주요 코드 포인트 설명

📐 시계 그리기: DrawClockFace

  • 외곽 원판: 중심 좌표(CX, CY), 반지름(R)
  • 눈금 & 숫자: Cos, Sin을 활용한 원형 배치
  • 중심 점: 작고 검은 원으로 표현
 
ang = (i / 12) * 2 * PI - PI / 2 x = CX + R * Cos(ang) y = CY + R * Sin(ang)

🔄 시간 바늘 그리기: UpdateClock

  • Now 함수로 시/분/초 추출
  • 각도 계산 후 AddLine으로 바늘 그리기
  • 기존 바늘은 삭제 후 새로 생성

🧪 실시간 동작 로직

 
nextTime = Now + TimeSerial(0, 0, 1) Application.OnTime earliesttime:=nextTime, procedure:="UpdateClock"
  • 매 1초 후 UpdateClock 다시 실행
  • Windows 시간과 싱크되어 정확하게 작동

⚠ 주의사항

항목설명
실행 중 중단 Alt + Break 또는 StopClock을 호출해야 완전히 중단됩니다.
다중 실행 여러 번 실행 시 바늘 중복 가능 → 중복 방지 코드 포함됨
파일 저장 매크로 포함 파일로 저장하세요 (.xlsm)

 

💬 마무리

"엑셀로 시계 만든다니... 진짜 될까?"

→ 됩니다!

 

아날로그 시계 만들기.xlsm
0.03MB