• 최초 작성일: 2000-09-22
  • 최종 수정일: 2026-09-30
  • 조회수: 18 회
  • 작성자: 권현욱 (엑셀러)
  • 강의 제목: 작업진척도 표시자 만들기

들어가기 전에

오래 전 엑셀 파일로 진행하던 강의를 웹 글로 복원한 것이라, "버튼을 눌러보세요"처럼 엑셀에서 직접 조작하라는 표현이 남아 있을 수 있습니다. 결과는 본문의 그림이나 표로 확인하실 수 있으며, 현재와 맞지 않는 내용은 보완하되 전반적인 스타일은 당시의 갬성(?)을 유지했습니다.

안녕하세요. 늘 변함없이 좋은 강좌를 진행해 주셔서 감사를 드립니다.
한 가지 궁금한 게 있는데요… VBA로 프로그램을 하나 짜서 실행을 시키는데
데이터가 좀 많다보니 시간이 엄청나게 오래 걸립니다. 보통 30분 이상이 걸립니다.

그런데, 지금 작업이 얼마나 진행이 되었는지, 아니면 어느만큼 진행이 되고 있는지
알 수 있는 방법이 없다보니 다운된게 아닌가 싶어 Ctrl + Alt + Del 키를 눌러 확인을
하곤 하는데 다른 무슨 방법이 없을까요?

있다면 꼭 좀 알려주세요. 다시 한번 감사합니다.

이 분 말고 두 분이 더 같은 질문을 하셨습니다.

두 가지 방법으로 해결해 보도록 하지요. 하나는 간단하게 상태표시줄을 활용하는 것, 다른 하나는 UserForm을 사용해서 보다 Visual하고 볼품있게 만들어 보는 것입니다. 아래 버튼들을 눌러서 실행시켜 보세요.

권현욱(엑셀러)
저자: 권현욱(엑셀러), 아이엑셀러 대표

필자는 Excel 컨설턴트, 작가, 그리고 크리에이터입니다. 현재 Microsoft Excel MVP이며, 『챗GPT+엑셀 업무자동화 정석』을 비롯한 10여 권의 도서를 집필했습니다. Excel 자동화 및 생산성 향상 분야에서 25년 넘는 경력을 보유하고 있습니다.

권현욱(엑셀러) 님의 최신 포스트:
  • 최신 글을 불러오는 중...


26년 경력 Microsoft MVP 권현욱(엑셀러) 대표 직강 1강 무료

🎁 파워툴스 마스터클래스 · 엑셀 바이브 코딩

AI에게 말로 지시해서 '나만의 엑셀 도구'를 만들고 리본에 장착합니다.

  • 코딩 지식 없이 시작 · 코드는 AI가 작성
  • 엑셀 리본에 내 탭과 버튼을 만들고 XLAM으로 공유
  • 1강 무료 수강 가능
수강 신청하기 강의 소개 보기

작업진척도 표시자 만들기

핵심 요약: 작업진척도 표시자

간단하게는 상태표시줄에, 보기 좋게는 UserForm의 레이블 폭을 바꾸어 작업 진행률을 표시합니다.

  • 방법 1: Application.StatusBar에 진행률 문자열을 대입합니다.
  • 방법 2: Frame 안의 Label 폭을 진행률만큼 늘려 막대를 그립니다.
  • 핵심: Activate 이벤트에서 시작하고 Repaint로 화면을 갱신합니다.

방법 1: 상태표시줄 활용하기

이것은 아주 간단한 몇 줄의 코딩만으로 작성을 한 것입니다. 단점이라면 진척도가 화면의 한쪽 모서리에 표시되기 때문에 눈에 잘 안띈다는 것과, 모든 것이 Visual화 해가는 이 마당에 그다지 Visual하지 못한 모양새라는 점!

하지만 코드는 아주 간단합니다. 코드는 어려운 것이 하나도 없습니다. For~Next문과 Select Case문을 사용했군요.

Sub ProgressIndicator1()
    Dim i As Long
    Dim strTemp As String
    Application.DisplayStatusBar = True
    '//상태표시줄을 화면에 표시합니다.

    For i = 0 To 30000
        Select Case i
            Case 0 To 10000
                strTemp = "1단계:   " & Format(i / 30000, "0.0%") & " 진행중..."
            Case 10001 To 20000
                strTemp = "2단계:   " & Format(i / 30000, "0.0%") & " 진행중..."
            Case 20001 To 30000
                strTemp = "3단계:   " & Format(i / 30000, "0.0%") & " 진행중..."
            '//순환문을 돌면서 각 Case별로 해당되는 값을 strTemp라는 변수에 담아둡니다.

        End Select
        Application.StatusBar = strTemp
        '//각 Case별로 strTemp 변수에 저장되어 있는 값을 상태표시줄에 뿌려줍니다.
    Next i
    Application.StatusBar = ""
    '//작업이 끝났으면 상태표시줄에 아무 것도 남아있지 않도록 공란을 대입합니다.

    MsgBox "작업이 끝났습니다", vbInformation, "작업진척도 표시//Exceller"
End Sub

방법 2: UserForm으로 시각적인 진척도 만들기

(방법 2)가 훨씬 보기가 좋지요? "그렇긴 한데 만들려면 더 복잡하겠네요?" 당연히 "그렇습니다!" 한 송이 국화꽃을 피우려면 봄부터 소쩍새가 몹시 시끄럽게 울어야 하지요. ^^

진척도 표시자용 UserForm: Label1, Frame1, 빨간 막대 Label
아이엑셀러

이 그림은 조금 전에 보신 작업진행 표시자를 구현하기 위한 UserForm입니다. 먼저 이것을 만듭니다. 아래의 순서대로 따라하세요.

(1) VB Editor 상태에서 UserForm을 하나 삽입합니다.

(2) Label 컨트롤을 하나 그립니다. 이것은 현재 어떤 작업을 하고 있는지를 사용자에게 알려주기 위한 것입니다. 프로그램 실행시에 "OOO번 작업 진행중…"이라는 메시지가 나타났었지요? 바로 그 부분입니다.

(3) 프레임 컨트롤을 또 하나 삽입한 다음(Frame1), 크기를 적당하게 조절합니다.

(4) 이번에는 (3)에서 작성한 프레임 내부에 Label컨트롤을 삽입합니다(위 빨간 막대). 이 때, 이 레이블의 폭(길이)은 얼마가 되든지 상관없습니다. 그림처럼 적당한 크기로 하나 만듭니다.

위의 그림에서 보면, Frame1과 레이블(빨간 막대)을 보면 입체감이 있지요? 이것은 이 컨트롤의 SpecialEffect 속성(프로퍼티)을 조절한 것입니다. 속성창의 SpecialEffect 프로퍼티를 적당한 것으로 지정해 보세요.

이제 필요한 컨트롤을 그리는 작업은 이것으로 끝났고… 각 컨트롤에 지능을 부여해 주는 작업입니다.

(5) Activate 이벤트

(5) UserForm 중에서 컨트롤이 없는 빈 영역을 더블클릭 합니다. 그러면 UserForm_Click 이벤트가 생성이 되는데 "이벤트 선택상자"에서 Activate Activate 이벤트를 선택합니다. 이렇게 하면 UserForm_Activate라는 새로운 이벤트가 발생됩니다. 이 이벤트에 아래의 코드를 입력합니다.

Private Sub UserForm_Activate()
    Call ProgressIndicator2
    '//ProgressIndicator2라는 다른 프로시저를 호출합니다.
End Sub

지금까지 Initialize 이벤트에 대해서는 여러 차례 설명을 드렸는데 Activate 이벤트에 대해서는 처음 알려 드리는 것 같군요. 이 두 가지 이벤트의 차이는 무엇이냐?

한 마디로 말하자면,

Initialize 이벤트는 유저폼이 화면 상에 display되기 전에 작동을 하는 이벤트입니다. 이에 반해 Activate 이벤트는 유저폼이 화면 상에 활성화되어 나타난 이후에 작동을 하는 이벤트입니다.

아래 코드에서 보시는 바와 같이 이 프로시저는 값이 바뀔 때마다 Repaint 메서드를 사용하게 되는데 만약에 Activate 이벤트가 아닌 Initialize를 사용한다면 화면 상에는 아무런 변화없이, 작업을 컴퓨터 내부적으로 다 끝낸 다음에야 결과를 화면상에 덜렁 뿌려주게 될 것입니다.

무슨 소린지 이해가 안 가는 분은 UserForm_Activate 이벤트를 UserForm_Initialize로 바꾼 다음 실행시켜 보시기 바랍니다. 아마 좀전에 보신 빨간색의 작업상태 표시자는 보이지 않고, 한참 있다가 메시지 박스만 하나 덜렁 나타나서 작업이 끝났다고 알려줄 것입니다.

(6) ProgressIndicator2 프로시저

(6) 이제 ProgressIndicator2 프로시저를 만들어야 겠지요? 아래의 코드를 입력합니다. 이 프로시저는 이벤트 핸들러 프로시저가 아니므로 Module 시트를 하나 삽입한 다음, 거기다가 입력합니다(사실 코드창에 입력해도 상관은 없습니다).

Sub ProgressIndicator2()
    Dim i As Long
    Dim PCT
    '//For~Next 순환문과 Select Case문을 사용하는 점은 ProgressIndicator1과 같습니다
    '//다만 이 프로시저에서 또다른 외부 프로시저인 UpdateIndicator를 호출하는데, 이 때
    '//PCT와 I라는 두 개의 변수를 파라미터(parameter), 즉 매개변수로 전달한다는 점이
    '//다릅니다.

    For i = 1 To 3000
        Select Case i
            Case 1 To 1000
                PCT = i / 3000
                Call UpdateIndicator(PCT, i)
            Case 1001 To 2000
                PCT = i / 3000
                Call UpdateIndicator(PCT, i)
            Case 2001 To 3000
                PCT = i / 3000
                Call UpdateIndicator(PCT, i)
            '//자신이 하고자 하는 작업을 바로 이 부분에 넣어주면 되겠지요?
        End Select
    Next i
    Unload UserForm1
    MsgBox "작업이 끝났습니다", vbInformation, "http://www.iexceller.com"
End Sub

(7) UpdateIndicator 프로시저

(7) 이번에는 위의 단계에서 호출한 프로시저인 UpdateIndicator를 작성합니다. 복잡하지요? "한 프로시저에 죄다 기입하면 되지 뭐가 이 프로시저는 저 프로시저를, 저 프로시저는 또다른 그것을 불러오고... 이거 일부러 복잡하게 코드를 짜서 모르는 사람 기 죽일려는 것 아냐?"

혹시 이렇게 생각하는 분이 있으신지? 코드는 될수 있는 한 토막토막 내서 작성하는 것이 여러가지 면에서 좋습니다. 나중에 나중에 다시 살펴볼 때에나 유지보수 할 때 훨씬 편리하지요.

Sub UpdateIndicator(PCT, i)
    With UserForm1
        .Label1.Caption = i & " 번 작업 진행중..."
        .frmProgress.Caption = Format(PCT, "0%")
        .lblProgress.Width = PCT * (.frmProgress.Width - 15)
        .Repaint
        '//PCT와 I라는 매개변수를 받아서 Label1의 캡션과 frmProgress의 캡션을 바꾸어 줍니다.
        '//그리고 lblProgress(빨간 막대이지요) Label의 폭을 변동시켜 줍니다. 이 부분은 아실테고…

        '//Repaint 메서드가 사용된 점에 주의하시기 바랍니다. 이 메서드는 설명을 드리지 않아도
        '//짐작을 하시겠지요? Repaint, 그러니까 색칠을 다시하는 메서드겠지요?
        '//만약 Repaint 메서드를 사용하지 않는다면 어떻게 될까요? 당연히 lblProgress 레이블이
        '//Updating 되지 않겠지요?
    End With
End Sub

(8) UserForm을 호출하는 프로시저

(8) 마지막으로, 이 UserForm을 호출할 프로시저를 작성합니다.

Sub ShowUserForm()
    With UserForm1
        .lblProgress.Width = 0
        '//유저폼을 불러올 때 lblProgress 즉 빨간 막대의 폭을 0으로 지정합니다. 처음 시작하니까
        '//길이를 0으로 하는 것이 맞겠지요? 이렇게 0으로 해 주기 때문에 (4)단계에서 레이블 폭은
        '//얼마가 되든지 상관없다고 한 것입니다.

        .Show
    End With
End Sub

작동 순서 정리

이제 끝났습니다. 어떤 순서로 작동이 되는지 잘 정리해 두시기 바랍니다.

맨 처음 ShowUserForm 프로시저를 실행하면 lblProgress 레이블의 폭을 0으로 하고 유저폼을 화면에 display 합니다. 그러면 유저폼의 Activate 이벤트가 실행되는데, 이 때 ProgressIndicator2 프로시저가 호출(triggered)되어 해당코드를 실행하고 다시 UpdateIndicator 프로시저를 호출하는데 이 때 Repaint 메서드를 통해 lblProgress 레이블의 Width를 지속적으로 변경시켜 줌으로써 화면상에서 진척도가 변화되는 것처럼 보이도록 하는 것입니다.

마치 정지된 필름을 초당 30 프레임의 속도로 돌리면 움직이는 것처럼 보이는 것과 같은 이치라고 할 수 있겠습니다.

마무리

오늘은 여기까지…

정리 — 진척도 표시자 핵심

구분 사용한 코드 역할
상태표시줄 Application.StatusBar = strTemp 진행률 문자열 표시
이벤트 UserForm_Activate 폼 표시 후 작업 시작
막대 폭 lblProgress.Width = PCT * (Frame폭 - 15) 진행률만큼 막대 늘림
화면 갱신 .Repaint 변경 내용 즉시 표시
초기화 lblProgress.Width = 0 막대를 0에서 시작

자주 묻는 질문 (FAQ)

Q1. Initialize 이벤트와 Activate 이벤트는 어떻게 다른가요?

Initialize는 유저폼이 화면에 표시되기 전에, Activate는 화면에 활성화되어 나타난 이후에 작동합니다.

Q2. Repaint 메서드를 사용하지 않으면 어떻게 되나요?

lblProgress 레이블의 폭이 화면에 갱신되지 않아 진행 막대가 늘어나는 모습이 보이지 않습니다.

Q3. 작업이 끝나면 상태표시줄은 어떻게 되돌리나요?

Application.StatusBar에 빈 문자열을 대입하면 상태표시줄이 원래대로 돌아갑니다.

마치며

긴 작업일수록 진행 상황을 보여 주는 것만으로도 사용자의 불안을 크게 덜어 줄 수 있습니다.