for each의 경고

VBA Tipz 2017. 1. 12. 20:34



VBA 에서

슬라이드(1) 내에서 모든 Shape 을 삭제한다고 할 때  for each를 써서 아래와 같이 해봅시다.

dim shp as Shape

for each shp in ActivePresentation.Slides(1).Shapes

shp.delete

next shp

실행해보면 다 사라질까요?

안타깝게도 의도와 달리 모두다 사라지지 않습니다.

절반 정도만 사라집니다.

왜 그럴까요?


첨부한 PPTM 을 매크로를 허용하고 열어봅시다.

'살펴보기' 화살표를 누릅니다.



도형추가를 눌러 랜덤한 위치에 도형을 10개 만들었습니다.


그다음 도형삭제(for each를 사용)을 클릭하여 도형을 삭제해봅시다.

내부적으로 아래 소스대로 작동합니다.


Dim shp As Shape

    For Each shp In ActivePresentation.Slides(CurSlide).Shapes

       If Left(shp.Name, 4) = "Box_" Then shp.Delete

    Next

그러나 지우고 남은 개체수가 9개나 됩니다.

여러번 눌러서 삭제해야 남은 개체가 4개로 다 사라집니다.

(생겨난 도형 외에 기본 도형이 4개입니다.)



이 현상은 왜 일어날까요?

???

for each 에서 1번개체를 지우는 순간 

다른 개체들의 배열이 한칸 앞으로 당겨지면서

2번 개체는 1번 개체가 되어버려 2번은 건너 뛰고 3번 개체가 다음 지울 차례가 되어버립니다.

그래서 첫번째 삭제 버튼을 눌렀을 때 2,4,6,8,10번 개체는 지워지지 않고 남게 됩니다.



이런 현상을 극복하는 방법을 알아봅시다.

'다음방법' 화살표를 눌러봅시다.



똑같이 도형추가를 누르고 도형을 생성합니다.

도형삭제 (거꾸로 for이용)를 눌러봅시다.


이번에 기본 도형 4개만 남고 모두 삭제가 됩니다.


Dim i As Single

    With ActivePresentation.Slides(CurSlide)

        For i = .Shapes.COUNT To 1 Step -1

            If Left(.Shapes(i).Name, 4) = "Box_" Then .Shapes(i).Delete

        Next

    End With



위와 같이 for each 를 사용하지 않고 
또한 for 문을 아래에서부터 돌지 않고
맨 끝번째 개체부터 시작하고 있습니다.

이렇게 맨 마지막 개체부터 차례로 아래로 내려가면서 지워야 개체의 순서가 영향을 받지 않습니다.
For i = 1 to .Shapes.Count 로 아래서부터 위로 올라가도 For Each 와 마찬가지로 누락이 발생합니다.
개체는 연속된 배열처럼 들어 있기 때문에 중간에 삭제하면 다음 번 개체의 순서가 당겨져서 우리의 생각과 다르게 누락이 발생하는 것이죠. 

제 경우엔
Shape(i).Visible = MsoFalse 로 해서 보이지 않는 개체를 많이 만들어서 For Each 로 처리했다가 
파워포인트슬라이드에 보이지 않는 개체가 계속 쌓여버려서 
파워포인트 파일이 저장이 안되는 에러가 발생해서 고생를 한 적이 있습니다.


특히 For Each 를 이용하거나 배열을 아래서 부터 위로 다룰 때 
위와 같이 중간에 배열 순서가 당겨져서 누락되어 오류가 발생할 수 있어서 
유의하여야 합니다.


이 글은 http://cafe.naver.com/gameppt/122333 에도 게재되었습니다.