Contents 호환성 문제의 정의와 증상 분류 즉시 조치 체크리스트(빠른 복구) 파일 형식별 특성과 선택 기준 버전 차이로 인한 기능 손실과 대체 전략 조직 환경 차이: 32/64비트, 추가기능, 보안 정책 CSV·텍스트 파일 호환성: 인코딩·구분 기호·서식 날짜·숫자 변형 방…
글 전체 보기- 공유 링크 만들기
- X
- 이메일
- 기타 앱
Contents 호환성 문제의 정의와 증상 분류 즉시 조치 체크리스트(빠른 복구) 파일 형식별 특성과 선택 기준 버전 차이로 인한 기능 손실과 대체 전략 조직 환경 차이: 32/64비트, 추가기능, 보안 정책 CSV·텍스트 파일 호환성: 인코딩·구분 기호·서식 날짜·숫자 변형 방…
글 전체 보기이 글의 목적은 엑셀 VBA에서 Application.ScreenUpdating 속성이 꺼졌음에도 화면 깜빡임이나 스크롤, 시트 재그림이 발생하는 문제를 체계적으로 진단하고, 재현 가능한 원인별 해결책과 실무형 코드 패턴을 제공하여 성능과 안정성을 동시에 확보하도록 돕는 것이다.
ScreenUpdating=False는 엑셀이 “화면을 다시 그림”을 억제하도록 지시하는 옵션이다. 그러나 다음 조건에서는 강제 리프레시가 트리거되어 깜빡임이 발생하거나 옵션이 무력화되는 것처럼 보일 수 있다.
PrintPreview, ExportAsFixedFormat(PDF), CopyPicture, CalculateFullRebuild, Find/Replace UI, 일부 Shapes 조작 등은 내부적으로 다시 그리기를 요청한다.DoEvents는 페인팅 메시지를 처리하여 일시적으로 화면이 그려질 수 있다..Select, .Activate, Application.Goto, ActiveWindow.ScrollRow/Column 등은 뷰포트를 변경한다.True로 되돌리는 코드가 실행되지 않으면 사용자가 수동으로 작업하는 동안 화면이 계속 갱신되어 “작동하지 않는 것”처럼 보인다.Worksheet_Change, Calculate 등 이벤트에서 다시 그리기를 유발하는 코드가 중첩 호출된다.SeriesCollection 대량 변경, 이미지 배치 등은 일부 버전에서 재도색을 요청한다.FreezePanes 토글, ArrangeWindows, Split 변경은 창 레이아웃을 다시 계산한다.Application.Calculation=xlAutomatic 상태에서 대량의 수식 셀 갱신은 내부 타이밍에 따라 페인트를 동반한다.ScreenUpdating=False는 “화면 그리기 억제 힌트”일 뿐 강제적 프레임 락이 아니다. 특정 메서드는 이를 우선한다.| 증상 | 가능 원인 | 즉시 점검 | 해결 1순위 |
|---|---|---|---|
| 깜빡임 지속 | 선택 이동, 스크롤 | .Select/.Activate 호출 여부 | 셀·개체 직접 참조로 치환 |
| PDF 저장 중 깜빡임 | ExportAsFixedFormat | 해당 호출 전후 옵션 상태 | 별도 숨김 창로 오프로딩 |
| 도중에만 깜빡임 | DoEvents 사용 | DoEvents 위치 파악 | 핵심 구간에서는 제거 |
| 옵션이 원복되지 않음 | 에러 핸들링 없음 | On Error 유무 | Finally 패턴 적용 |
| 이벤트 루프 반복 | EnableEvents=True | 이벤트 내부 호출 체인 | EnableEvents=False로 보호 |
| 차트만 깜빡임 | 축 자동맞춤 | 축 자동 스케일 상태 | 수정 전 자동맞춤 잠시 끄기 |
핵심은 “입장-핵심 작업-정리” 3단계이다. 모든 UI·계산·이벤트 옵션을 원자적으로 관리하고, 오류 발생 시에도 반드시 복원하도록 한다.
Public Sub DoWork_Safe() Dim s As Boolean, c As XlCalculation, e As Boolean, a As Boolean, d As Boolean On Error GoTo EH
' 1) 입장: 상태 스냅샷
With Application
s = .ScreenUpdating
c = .Calculation
e = .EnableEvents
a = .DisplayAlerts
d = .DisplayStatusBar
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
.DisplayStatusBar = False
.Calculation = xlCalculationManual
.Cursor = xlWait
End With
' 2) 핵심 작업: 선택 이동 금지, DoEvents 최소화
CoreWorkNoSelect
' 3) 정리: 정상 종료 복원
GoTo Finally
EH:
' 오류 로깅 등 처리
Finally:
With Application
.Calculation = c
.EnableEvents = e
.DisplayAlerts = a
.DisplayStatusBar = d
.ScreenUpdating = s
.Cursor = xlDefault
.StatusBar = False
End With
End Sub
Private Sub CoreWorkNoSelect()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("데이터")
' 나쁜 예: ws.Range("A1").Select : Selection.Value = 1
' 좋은 예:
ws.Range("A1").Value = 1
' 필요 시 범위 쓰기 일괄 처리
Dim arr
arr = ws.Range("A1:C100").Value
' ... 배열에서 계산 ...
ws.Range("A1:C100").Value = arr
End Sub
.ScreenUpdating=False 이후에도 .Select를 사용하면 뷰포트가 이동하여 사용자는 “화면이 바뀐다”고 인식한다. 셀·도형은 객체 직접 지정으로 조작해야 한다.' 나쁜 예 Rows("1:1").Select Selection.Insert
' 좋은 예
Rows("1:1").Insert
' 나쁜 예
Application.Goto Worksheets("보고서").Range("B2"), True
Worksheets("보고서").Range("B2").Value = "완료"
' 좋은 예
Worksheets("보고서").Range("B2").Value = "완료"
' 나쁜 예
Charts("매출").Activate
ActiveChart.Axes(xlValue).MaximumScale = 100
' 좋은 예
With Charts("매출")
.Axes(xlValue).MaximumScale = 100
End With
DoEvents는 UI 응답성을 높이지만 페인팅 메시지 처리로 순간적인 그리기를 허용한다. 장시간 루프에서는 주기적으로 쓰되, 대량 쓰기·서식 변경 등 “플러딩” 구간에서는 제거하거나 호출 간격을 늘려야 한다.
Dim i As Long For i = 1 To 100000 ' 핵심 연산 If (i Mod 2000) = 0 Then DoEvents ' 지나친 호출 금지 Next i ExportAsFixedFormat와 CopyPicture는 내부 렌더 파이프라인을 강제한다. 다음 전략으로 영향도를 줄인다.
Sub ExportPDF_Offscreen() Dim wb As Workbook, tmp As Workbook Set wb = ThisWorkbook wb.Worksheets("보고서").Copy Set tmp = ActiveWorkbook ' 새로운 임시 통합 문서 With Application .ScreenUpdating = False .DisplayAlerts = False End With tmp.Worksheets(1).ExportAsFixedFormat Type:=xlTypePDF, Filename:="C:\out.pdf" tmp.Close SaveChanges:=False Application.DisplayAlerts = True Application.ScreenUpdating = True End Sub 이벤트 프로시저에서 다시 ScreenUpdating을 켜거나 선택 이동을 수행하면 깜빡임이 심해진다. 이벤트 내부에서는 최소 작업만 수행하고, 대량 처리는 별도 프로시저로 위임한다.
Private Sub Worksheet_Change(ByVal Target As Range) On Error GoTo ExitHere Application.EnableEvents = False ' 최소 검증만 수행 If Not Intersect(Target, Range("A:A")) Is Nothing Then ValidateInput Target End If ExitHere: Application.EnableEvents = True End Sub 자동 계산이 켜진 상태에서 대량의 셀 값을 갱신하면 내부 배치 계산 시점에 일부 화면 반응이 나타날 수 있다. 다음 규칙을 권장한다.
Calculation=Manual로 전환하고 종료 시 원복한다.Calculate 대신 필요한 범위에 국한한다.With Application .Calculation = xlCalculationManual .ScreenUpdating = False End With
' ... 대량 작업 ...
Range("B2:B10000").Calculate ' 필요한 범위만
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
차트 엔진은 축 자동 맞춤과 레이아웃 계산을 수행한다. 대량 변경 시에는 일시적으로 자동을 꺼두고, 변경 후 한 번만 다시 계산하도록 한다.
Sub QuietChartEdit() Dim ch As ChartObject Set ch = Worksheets("대시보드").ChartObjects("매출차트") With Application .ScreenUpdating = False End With With ch.Chart .Axes(xlCategory).HasTitle = False .Axes(xlValue).MaximumScaleIsAuto = False .Axes(xlValue).MaximumScale = 100 ' Series 대량 추가·삭제 수행 End With ' 필요 시 마지막에만 Refresh ch.Chart.Refresh Application.ScreenUpdating = True End Sub 다중 창(New Window)이 열려 있거나 프리즈창이 활성화된 워크시트에서 셀 삽입·삭제·필터 변경 등 뷰 변형을 수행하면 화면 갱신이 가시화될 수 있다. 다음 절차를 참고한다.
FreezePanes를 임시 해제한다.Sub WithFreezePanes() Dim wasFrozen As Boolean With ActiveWindow wasFrozen = .FreezePanes If wasFrozen Then .FreezePanes = False End With
' ... 구조 변경 작업 ...
If wasFrozen Then ActiveWindow.FreezePanes = True
End Sub
UserForm이 표시된 상태에서 워크시트 조작을 수행하면 폼 페인트와 워크시트 페인트가 상호 작용한다. 모달 폼을 쓰는 경우 폼 표시 전후로 핵심 작업을 분리하는 것이 안전하다. 모델리스 폼은 빈도 낮은 타이머 기반 리프레시만 허용한다.
' 폼 열기 전 데이터 준비를 끝낸다 PrepareDataFast UserForm1.Show vbModal 화면 그리기를 막는 것보다 변경 횟수를 줄이는 편이 더 효과적이다. 다음 설계를 권장한다.
For Each Cell 대신 Variant 2차원 배열 사용..Interior.Color, .Font.Bold 등은 영역 단위로 적용.' 나쁜 예: 행마다 색칠 Dim r As Range For Each r In Range("A2:A100000") If r.Value >= 0 Then r.Interior.Color = RGB(220,255,220) Next
' 좋은 예: 사전 계산 후 일괄 서식
With Range("A2:A100000")
.FormatConditions.Delete
.FormatConditions.Add Type:=xlCellValue, Operator:=xlGreaterEqual, Formula1:="=0"
.FormatConditions(1).Interior.Color = RGB(220,255,220)
End With
모든 모듈의 공통 유틸리티로 두고 재사용하면 휴먼 에러를 크게 줄일 수 있다.
Public Type AppState ScreenUpdating As Boolean EnableEvents As Boolean DisplayAlerts As Boolean DisplayStatusBar As Boolean Calculation As XlCalculation End Type
Public Sub WithAppQuiet(ByVal work As String)
Dim st As AppState
On Error GoTo EH
Snapshot st
QuietOn
Application.StatusBar = work
' << 핵심 작업 호출 지점 >>
GoTo Finally
EH:
' 로깅 가능
Finally:
Restore st
End Sub
Private Sub Snapshot(ByRef st As AppState)
With Application
st.ScreenUpdating = .ScreenUpdating
st.EnableEvents = .EnableEvents
st.DisplayAlerts = .DisplayAlerts
st.DisplayStatusBar = .DisplayStatusBar
st.Calculation = .Calculation
End With
End Sub
Private Sub QuietOn()
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
.DisplayStatusBar = False
.Calculation = xlCalculationManual
.Cursor = xlWait
End With
End Sub
Private Sub Restore(ByRef st As AppState)
With Application
.Calculation = st.Calculation
.EnableEvents = st.EnableEvents
.DisplayAlerts = st.DisplayAlerts
.DisplayStatusBar = st.DisplayStatusBar
.ScreenUpdating = st.ScreenUpdating
.Cursor = xlDefault
.StatusBar = False
End With
End Sub
| 원인 | 해결책 | 코드 스니펫 |
|---|---|---|
| 선택 이동 | 객체 직접 참조 | Range("A1").Value=1 |
| DoEvents 과다 | 호출 간격 증가/핵심 구간 제거 | If i Mod 2000 = 0 Then DoEvents |
| PDF 출력 | 임시 워크북에서 출력 | Worksheets(1).ExportAsFixedFormat ... |
| 이벤트 재진입 | 이벤트 보호 | Application.EnableEvents=False |
| 자동 계산 | 수동 계산 전환 | Application.Calculation=xlCalculationManual |
| 차트 플리커 | 자동맞춤 잠정 해제 후 일괄 반영 | Axes(...).MaximumScaleIsAuto=False |
| 프리즈창 | 작업 전 해제 후 원복 | ActiveWindow.FreezePanes=False |
| 오류 후 상태 불일치 | Finally 복원 패턴 | On Error GoTo EH ... Finally: |
.Select/.Activate/Application.Goto 호출을 전수 조사하여 제거한다.DoEvents 호출 빈도를 낮춘다.간헐적 깜빡임은 특정 호출 조합에서만 발생한다. 문제가 되는 라인을 찾기 위해 이분 탐색 방식으로 로그를 삽입한다.
Debug.Print "T1: Before data write", Timer ' ... 코드 블록 A ... Debug.Print "T2: After data write", Timer ' ... 코드 블록 B ... Debug.Print "T3: Before chart edit", Timer 최소 재현 예제는 “하나의 프로시저, 하나의 시트, 데이터 10~100행” 수준으로 줄여서 공개 검토가 가능하도록 만든다.
작업 완료 후 ScreenUpdating=True로 복원하는 것만으로 충분하지 않다. 상태 표시줄 메시지, 커서, 선택 영역 등을 합리적으로 정리해야 사용자는 깔끔한 경험을 한다.
Application.StatusBar = "완료: " & Format(Now, "yyyy-mm-dd hh:nn:ss") Application.Cursor = xlDefault ' 선택 복원 필요 시 ThisWorkbook.Worksheets("대시보드").Range("A1").Select ' 선택 복원도 최소화 권장 코드에 .Select, .Activate, Application.Goto 혹은 ScrollRow/ScrollColumn을 직접 호출했을 가능성이 높다. 해당 구문을 제거하고 객체 직접 참조로 치환해야 한다.
아니다. 장시간 연산에서 무응답 방지를 위해 제한적으로 사용한다. 다만 대량 쓰기·서식 적용 구간처럼 페인트가 발생하기 쉬운 부분에서는 호출 빈도를 낮추거나 제거한다.
내부 렌더 과정은 완전 차단이 어렵다. 임시 통합 문서에서 출력하거나, 출력 범위를 최소화하여 체감 깜빡임을 크게 줄일 수 있다.
이벤트가 연쇄적으로 발생하면 다른 핸들러에서 선택 이동·계산·폼 갱신 등을 수행할 수 있다. 진입 시 EnableEvents=False로 보호하고 대량 작업은 이벤트 밖에서 실행한다.
축 자동맞춤을 일시 해제하고 시리즈 변경을 한 번에 적용한 뒤 마지막에 한 번만 .Refresh를 호출하는 것이다.