[Excel] 10. 엑셀로 능력있는 직장인이 되는 법. 엑셀 그림판에 애니메이션 기능 추가하기!

gbgg(54)
Published in
#kr-dev
Words
1183
Reading
6 min
Listen
Play
9y

안녕하세요! gbgg@gbgg 입니다. 능력있는 직장인이 되는법!

엑셀 자동화 강의가 벌써 열번째입니다! 사실 어떻게 보면 많이 관심 없으실 만한 분야라서

어떤 컨텐츠로 강의를 진행해야할까 고민 많이했었는데 많이 좋아해주셔서 보람차고 기쁩니다 :)

지난 9번 강좌에서 진행했던 그림판 만들기에서 어떤 기능을 추가하면 좋을까 생각하다가

애니메이션 기능을 넣어보면 어떨까 하는 생각에 한번 만들어보게 되었습니다.

애니메이션이라고 해서 어렵게 느끼실 수 있으실 것 같은데, 지난 강의들에서 진행했던

데이터 불러오고 기록하는 단순한 방법으로 만들 수 있는 것이라 쉽게 이해하실 수 있으실

것이라고 생각합니다! :)

오늘 진행할 강의내용의 핵심은 두 가지 입니다!

  • 도트데이터 저장하고 불러오기
  • 엑셀 렉 줄이기 & 지연시간 활용

조금 난이도가 있으니 천천히 잘 따라와주세요! 지난번처럼 예제파일도 첨부하겠습니다!

강의가 끝나면 요런 애니메이션도 만드실 수 있을 겁니다!

에비츄.gif


기본 셋팅

가장 먼저 데이터의 양이 어느정도 될지 체크해보겠습니다.

52 * 52 = 2,704개의 픽셀로 이루어져 있습니다.

그렇다면 별도의 최적화를 하지 않는 이상 한 그림에 2,704개의 픽셀 데이터 값이 저장될 겁니다.

생각보다 데이터 양이 많아보입니다.

하지만 엑셀의 vba는 그 이상의 데이터도 빠르게 처리할 수 있기 때문에 걱정하지 않으셔도 됩니다.

이제 작업을 어떤식으로 진행할 지 기능별로 정리해보겠습니다.

그림 하나당 2,704개의 데이터를 저장해야합니다.

가장 좋은 방법은 시트 하나에 에니메이션 횟수만큼 데이터를 이어서 저장하는 것 이지만

이번 강의에서는 기본 개념을 위해 시트 3개를 만들어 각 시트에 저장해보겠습니다.

  • DATA1, 2, 3 시트를 만들어 이곳에 데이터 저장

데이터를 저장하려면 캔버스에 어떤 그림이 저장되어있는지 먼저 파악해야합니다.

픽셀 개념이기 때문에 FOR 반복문 두개를 사용해서 X축과 Y축의 값을 가져오려고 합니다.

  • X축과 Y축 픽셀의 색상 값 검사

저장된 데이터가 있으니 불러오기도 구현해야겠죠?

불러오기는 저장의 역순이라고 생각하시면 됩니다.

시트에 저장된 2,704개의 데이터들을 하나 씩 순차적으로 픽셀에 그려주면 됩니다.

픽셀에 그리기 앞서 기존에 있던 픽셀 그림들을 삭제해야합니다. 이 부분은 이전 시간에 배운 매크로를 활용해서 코드를 복사해 사용하겠습니다.

  • DATA1, 2, 3에 있는 데이터 값을 순차적으로 불러 캔버스에 표시
  • 캔버스에 있는 색상을 모두 빈 바탕색으로 변경 (매크로 활용)

불러오기 기능까지 구현되었다면 애니메이션은 간단합니다.

이번 포스팅에서는 총 3개의 픽셀데이터가 존재하는데 이 데이터들을 순차적으로 불러오면 됩니다.

화면클리어 -> 1번불러오기 -> 화면클리어 -> 2번불러오기....

방식으로 코드를 작성하면 되고 중간중간에 지연시간을 넣어 이모티콘처럼 작동하도록 구현해보겠습니다.

위 그림과 같이 버튼 3개를 배치하고 숫자를 써 넣을 셀 두개의 공간을 만듭니다.

픽셀 데이터를 넣을 시트 (DATA1, DATA2, DATA3)을 만듭니다.

DATA시트의 양식은 다음과 같이 NO와 RGB로 구성하겠습니다.


저장하기

저장 기능을 구현하기에 앞서 알고리즘을 말로 한번 풀어 써 보겠습니다.

픽셀 그림판은 이렇게 X, Y축으로 볼 수 있습니다.

이 데이터를 저장하려면 어떤 순서로 해야할까요?

저는 아래와 같은 순서대로 컬러 값을 뽑아보겠습니다.

(Y,X)라 가정할 때 위 그림같은 순서대로 좌표값을 찾아낼 수 있습니다.

일반적으로 이럴 때는 FOR 반복문을 두번 중첩시켜 읽어내는데 코드는 다음과 같습니다.

For i = 2 To 53
    For j = 2 To 53

    Next
Next

2부터 53까지 반복시킨 이유는 셀의 번호가 2부터 53까지이기 때문입니다.

1부터 52까지 두고 i + 1, j + 1 하는 방식도 있지만 여기서는 이렇게 코드를 짜 보겠습니다.

자 그렇다면 i값이 2고 j값이 2인 처음 부분에서 어떤 작업을 진행해줘야 할까요?

즉 저 RGB 부분에 (j , i)의 컬러 값을 넣어야 합니다. 이 작업을 2,704번 반복하면?

그림의 각각 픽셀 값을 모두 저장시킬 수 있습니다.

그렇다면 코드는 이런식으로 작성할 수 있을겁니다.

Sub 단추1_Click()
Sheets("DATA").Range("A2:B2706").ClearContents

For i = 2 To 53
    For j = 2 To 53
        cnt = Sheets("DATA").Range("A1").CurrentRegion.Rows.Count + 1
        Sheets("DATA").Cells(cnt, 1) = Val(Sheets("DATA").Cells(cnt - 1, 1)) + 1
        
        Sheets("DATA").Cells(cnt, 2) = Sheets("그림판").Cells(j, i).Interior.Color
    Next
Next
End Sub

.Interior.Color 부분만 제외하고 나머지는 지난 강의에서 진행했던 부분이니 살짝 넘어가보도록 하겠습니다.

.Interior.Color 코드는 해당 셀의 컬러값을 가져오는데 255,255,255 식으로 가져오는 게 아니고

색상마다 정해진 주소값을 가져오게 됩니다.

예를들어 하얀색은 16777215이 되고 검은색은 0이 됩니다.

하지만 이 값은 중요하지 않습니다. 어짜피 이 값을 그대로 적용시킬 것이기 때문에 모르셔도 됩니다.

Sheets("DATA").Range("A2:B2706").ClearContents 이 부분은 데이터를 저장시키기 전에

덮어씌우기 위해 기존에 있던 값을 모두 지웁니다.

코드를 작성하셨다면 버튼을 눌러보겠습니다.

잠깐의 렉? 이후에 DATA 시트로 가보면 이렇게 순서대로 값이 기록된 걸 확인하실 수 있을 겁니다.

DATA2와 DATA3도 추가해야겠죠?

이 BD30셀의 값이1이면 DATA, 2면 DATA2, 3이면 DATA3으로 저장되도록 해보겠습니다.

Sub 단추2_Click()

Dim cnt As Integer

If Sheets("그림판").Range("BD30").Value = "1" Then

Sheets("DATA").Range("A2:B2706").ClearContents

For i = 2 To 53

    For j = 2 To 53
        cnt = Sheets("DATA").Range("A1").CurrentRegion.Rows.Count + 1
        Sheets("DATA").Cells(cnt, 1) = Val(Sheets("DATA").Cells(cnt - 1, 1)) + 1
        
        Sheets("DATA").Cells(cnt, 2) = Sheets("그림판").Cells(j, i).Interior.Color
    Next
Next

ElseIf Sheets("그림판").Range("BD30").Value = "2" Then

Sheets("DATA2").Range("A2:B2706").ClearContents

For i = 2 To 53

    For j = 2 To 53
        cnt = Sheets("DATA2").Range("A1").CurrentRegion.Rows.Count + 1
        Sheets("DATA2").Cells(cnt, 1) = Val(Sheets("DATA2").Cells(cnt - 1, 1)) + 1
        
        Sheets("DATA2").Cells(cnt, 2) = Sheets("그림판").Cells(j, i).Interior.Color
    Next
Next

ElseIf Sheets("그림판").Range("BD30").Value = "3" Then

Sheets("DATA3").Range("A2 : B2706").ClearContents

For i = 2 To 53

    For j = 2 To 53
        cnt = Sheets("DATA3").Range("A1").CurrentRegion.Rows.Count + 1
        Sheets("DATA3").Cells(cnt, 1) = Val(Sheets("DATA3").Cells(cnt - 1, 1)) + 1
        
        Sheets("DATA3").Cells(cnt, 2) = Sheets("그림판").Cells(j, i).Interior.Color
    Next
Next
        
End If
        
End Sub

함수로 반복되는 부분을 만들어서 쓰면 길이를 줄일 수 있지만 3개밖에 안되기 때문에 간단하게 이렇게 코드를 작성해 보겠습니다. 위 코드를 복사하셔서 쓰시면 됩니다.


불러오기

불러오기기능은 생각보다 간단합니다. 그림으로 설명드릴게요!

아까 저장했던 데이터들을 가지고 그 위치의 픽셀 컬러값을 바꿔주기만 하면 됩니다.

저장하기랑 정확하게 반대죠? 그렇다면 어느 부분을 반대로 해야할까요?

왼쪽이 저장, 오른쪽이 불러오기 입니다. 빨간 부분은 바뀐 부분입니다.

cnt = 0 이기 때문에 임의로 +1을 해서 픽셀 위치값과 맞춰주었습니다.

  • 여기서 잠깐
    여기서 잠깐 버그가 발생하는데 분명

색이 없는 부분은 투명한 상태임에도 데이터에는 아까 하얀값 -> 16777215이 들어가게 됩니다. 이렇게 되면 사진을 불러왔을 때 배경이 흰색으로 덮이게 되는데요.

아직 테두리색을 설정하지 않았기 때문에 이 부분은 조건문으로 처리되지 않게 해줘야겠죠?

현재는 하얀색이 투명을 의미하기 때문에 조건문으로 걸러내주어야 합니다.

Sub 단추3_Click()

Dim cnt As Integer

Range("B2:BA53").Select
    With Selection.Interior
        .Pattern = xlNone
        .TintAndShade = 0
        .PatternTintAndShade = 0
End With

If Sheets("그림판").Range("BD36").Value = "1" Then

For i = 2 To 53

    For j = 2 To 53
               
        cnt = cnt + 1
        
        If Sheets("DATA").Cells(cnt + 1, 2).Value = 16777215 Then
         
        Else
        Sheets("그림판").Cells(j, i).Interior.Color = Sheets("DATA").Cells(cnt + 1, 2)
         
        End If
         
    Next
Next

ElseIf Sheets("그림판").Range("BD36").Value = "2" Then

For i = 2 To 53

    For j = 2 To 53
               
        cnt = cnt + 1
        
        If Sheets("DATA2").Cells(cnt + 1, 2).Value = 16777215 Then
         
        Else
        Sheets("그림판").Cells(j, i).Interior.Color = Sheets("DATA2").Cells(cnt + 1, 2)
         
        End If
         
    Next
Next

ElseIf Sheets("그림판").Range("BD36").Value = "3" Then

For i = 2 To 53

    For j = 2 To 53
               
        cnt = cnt + 1
        
        If Sheets("DATA3").Cells(cnt + 1, 2).Value = 16777215 Then
         
        Else
        Sheets("그림판").Cells(j, i).Interior.Color = Sheets("DATA3").Cells(cnt + 1, 2)
         
        End If
         
    Next
Next

End If

End Sub

위 코드를 붙여넣으시면 됩니다.

Range("B2:BA53").Select
    With Selection.Interior
        .Pattern = xlNone
        .TintAndShade = 0
        .PatternTintAndShade = 0
End With

위 코드 부분은 지난 9강에서 배운 매크로를 사용하여 B2열부터 BA53열을 선택 후 색상값을 투명하게 만드는 작업을 수행한 후 얻은 코드입니다.

그림을 불러오기 전에 기존에 그려져 있던 그림은 지우고 그려야겠죠?

위 코드까지 붙여넣으셨다면 다음과 같은 결과를 확인하실 수 있으실 겁니다.

gif1.gif


애니메이션

불러오기까지 이해가 가셨다면 애니메이션은 아주! 간단합니다.

불러오기 코드를 복붙하기만 하면 됩니다. 그림으로 한번 정리해 보겠습니다.

이렇게 해주면 되겠죠? 원리는 정말 간단합니다.

하지만 이렇게 하면 두 가지 문제가 발생합니다.

  • 엑셀이 과부하걸리면서 강제종료된다. (저장하지 않았다면 다 날라갑니다..ㅜㅜ)
  • 중간에 지연시간을 넣지 않았기 때문에 순식간에 프레임이 지나가버린다.

이 포스팅 초반에 제가 언급한 말이 있습니다.

'하지만 엑셀의 vba는 그 이상의 데이터도 빠르게 처리할 수 있기 때문에 걱정하지 않으셔도 됩니다.' 라고 말씀드렸었는데요.

아니 그런데 왜 과부하걸리는거죠?

엑셀은 정보 하나가 변경될 때 마다 시각적으로 모두 그 과정을 보여주도록 기본 셋팅되어있습니다.

우리는 2,704번의 그 변화를 계속해서 반복했는데 그 과정을 모두 보고 있었기 때문에

과부하가 걸려 이런 문제가 발생했던것입니다.

고맙게도 엑셀vba에서는 이 시각적으로 보는 기능을 켜고 끌수 있도록 만들어두었습니다.

Application.ScreenUpdating = False

Application.ScreenUpdating가 True 상태일때는 모두 시각적으로 표시됩니다.
Application.ScreenUpdating 가 False 상태일때는 작업이 완료된 후 표시됩니다.

그렇다면 이 코드를 껐다 켰다 하면 과부하를 막을 수 있을겁니다.

사이에 넣어보겠습니다.

이렇게 켜고 끄고를 반복하면 For문이 2704여번 반복하는 동안 시각효과가 꺼지게 되고

반복이 끝나면 시각적으로 보여줍니다.

이런식으로 사이에 넣어줌으로써 과부하를 방지할 수 있습니다.

이제 이 사이에 시간만 넣어주면 되겠죠?

start = Timer
    Do While Timer < start + 0.15
        DoEvents
    Loop

시간 함수는 간단합니다. Do while문을 사용하여 시간이 지나기전에 지나가지 못하도록 하는 방식인데요.

0.15라고 써져있는 부분만 수정해주시면 시간을 조절하실 수 있습니다.

단위는 1(초) 입니다. 저 부분에 10을 넣으면 10초가 되겠죠? 저는 0.15초로 셋팅하였습니다.

다음코드를 붙여넣어봅시다.

Sub 단추4_Click()

Dim cnt As Integer

Application.ScreenUpdating = False

For k = 1 To 5

    Range("B2:BA53").Select
    With Selection.Interior
        .Pattern = xlNone
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
Range("BL59").Select
    
      For i = 2 To 53
        For j = 2 To 53
               
        cnt = cnt + 1
        
        If Sheets("DATA").Cells(cnt + 1, 2).Value = 16777215 Then
         
        Else
        Sheets("그림판").Cells(j, i).Interior.Color = Sheets("DATA").Cells(cnt + 1, 2)
         
        End If
         
        Next
    Next
    
Application.ScreenUpdating = True

    start = Timer
    Do While Timer < start + 0.15
        DoEvents
    Loop
    
Application.ScreenUpdating = False
    cnt = 0
    
Range("B2:BA53").Select
    With Selection.Interior
        .Pattern = xlNone
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
Range("BL59").Select

    For i = 2 To 53
        For j = 2 To 53
               
        cnt = cnt + 1
        
        If Sheets("DATA2").Cells(cnt + 1, 2).Value = 16777215 Then
         
        Else
        Sheets("그림판").Cells(j, i).Interior.Color = Sheets("DATA2").Cells(cnt + 1, 2)
         
        End If
         
        Next
    Next
    
Application.ScreenUpdating = True
    
    start = Timer
    Do While Timer < start + 0.15
        DoEvents
    Loop
    
Application.ScreenUpdating = False
    cnt = 0

Range("B2:BA53").Select
    With Selection.Interior
        .Pattern = xlNone
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
Range("BL59").Select

    For i = 2 To 53
        For j = 2 To 53
               
        cnt = cnt + 1
        
        If Sheets("DATA3").Cells(cnt + 1, 2).Value = 16777215 Then
         
        Else
        Sheets("그림판").Cells(j, i).Interior.Color = Sheets("DATA3").Cells(cnt + 1, 2)
         
        End If
         
        Next
    Next
    
Application.ScreenUpdating = True
    
    start = Timer
    Do While Timer < start + 0.15
        DoEvents
    Loop
    
Application.ScreenUpdating = False
    cnt = 0

Range("B2:BA53").Select
    With Selection.Interior
        .Pattern = xlNone
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
Range("BL59").Select

    For i = 2 To 53
        For j = 2 To 53
               
        cnt = cnt + 1
        
        If Sheets("DATA2").Cells(cnt + 1, 2).Value = 16777215 Then
         
        Else
        Sheets("그림판").Cells(j, i).Interior.Color = Sheets("DATA2").Cells(cnt + 1, 2)
         
        End If
         
        Next
    Next
    
Application.ScreenUpdating = True

    start = Timer
    Do While Timer < start + 0.15
        DoEvents
    Loop
    
Application.ScreenUpdating = False
    cnt = 0

Next

Range("B2:BA53").Select
    With Selection.Interior
        .Pattern = xlNone
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
Range("BL59").Select

    For i = 2 To 53
        For j = 2 To 53
               
        cnt = cnt + 1
        
        If Sheets("DATA").Cells(cnt + 1, 2).Value = 16777215 Then
         
        Else
        Sheets("그림판").Cells(j, i).Interior.Color = Sheets("DATA").Cells(cnt + 1, 2)
         
        End If
         
        Next
    Next
    
Application.ScreenUpdating = True

End Sub

코드가 정말 긴데 불러오기 동작을 복사해서 여러번 붙여넣은 것 밖에는 없습니다.

원래는 이렇게 쓸데없이 길게 코딩하면 안됩니다 ;;

단순히 3번 반복하는 것이기 때문에 이렇게 작성하였고

다음 버전에서는 함수로 만들어서 짧게 코딩하겠습니다. (굽신굽신)

여기까지 잘 따라오셨나요? 한번 구동시켜보겠습니다.

gif2.gif

(죄송합니다.. 에비츄의 귀여움을 제대로 표현하지 못한 것 같습니다 ㅠ_ㅠ)

이렇게 그림을 그려 저장한 후 다양한 이모티콘?을 만들어낼 수 있습니다.

gif2.gif

지난 포스팅에 잠깐 등장한 라이언입니다.


엑셀 자동화

지난 시간에 진행했던 엑셀 그림판에 애니메이션 기능을 추가해보았습니다.

어느정도 코딩에 지식이 있으신 분들을 위한 강의가 된 것 같아서 다음 기초편에 부족했던

코드에 대한 설명을 마무리해볼까 합니다.

벌써 엑셀 자동화강의가 10강까지 진행되었는데요, 아직 알려드릴것들이 많습니다 ㅎㅎ;

포스팅을 작성하고 한번 쭉 훑어보는데 괜찮게 쓴 것 같아서 올리고나면

다음에 다시 볼 때 무언가 덜 쓴내용이나 이런것들이 눈에 보이더라구요 ㅠㅠ

앞으로 더 알찬 포스팅이 되도록 노력하겠습니다. 감사합니다!

필요하실 분이나 한번 해보고 싶으신 분들을 위해

안쓰는 네이버 블로그에 자료 올려놓았습니다.

다운로드 링크로 이동

필요하신 분 있으시면 받아가세용!

혹시 강의에 추가되었으면 하는 기능이 있다거나

조언해주실 부분이 있으시다면 댓글로 거침없이 피드백 주세요! 쓴소리 좋아합니다!

능력있는 직장인이 되기 위해 엑셀로 전산프로그램을 만들 때 까지 한번 열심히 달려봅시다!

다음 포스팅에서 뵙겠습니다!


지난 포스팅

[Excel] 1. 능력있는 직장인이 되는 법. 엑셀 자동화란?

[Excel] 2. 능력있는 직장인이 되는 법. 다른 파일 불러오기!

[Excel] 3. 능력있는 직장인이 되는 법. 물품 입고시키기!

[Excel] 4. 엑셀로 능력있는 직장인이 되는 법. 간편한 UI 만들기!

[Excel] 5. 엑셀로 능력있는 직장인이 되는 법. 로그인 + 접속기록 만들기!

[Excel] 6. 엑셀로 능력있는 직장인이 되는 법. 재고(자산) 관리용 현황판 만들기!

[Excel] 7. 엑셀로 능력있는 직장인이 되는 법. 초급편 (기초함수 소개)

[Excel] 8. 엑셀로 능력있는 직장인이 되는 법. 초급편 (VLOOKUP, INDEX, MATCH 등)

[Excel] 9. 엑셀로 능력있는 직장인이 되는 법. 그림판 만들기 ! (매크로 기록 활용)