본문 바로가기
VBA/엑사남_기초방

[기초방] VBA 100제 #16 [ 이벤트 + 빈셀삭제하기 ]

by 일등미노왕국 2023. 1. 16.

 

이러한 문제는 임시적으로 배열에 담았다가 출력을 하면 더 쉽게 가능하지만 아직은 배열과정이 아니기에 철저하게 셀기반으로 풀어보려 한다.

 

크루들이 과제를 풀어가는 것을 보니 일단 이벤트 개념은 확실히 잡고 가는거 같다.

본인이 공부할때는 이벤트가 참 어려웠다. 엑사남님 강의를 제대로 안 들은것도 있었지만 모듈에서 짜던 코드들이 시트를 넘나 드는것을 보면서 많이 힘들었던 기억이 있다. 엑사남님 강의를 정독으로 3번쯤 볼때 '아..이걸 왜 어려워했지' 했을 정도로 강의 자체를 쉽게 쉽게 하셨으니, 지금 잘 이해가 안 가는 분들은 꼭 강의를 정독하길 바란다. 

 

이벤트에서 Target 이라는 것은 쉽게 말해서 selection  이라고 생각하면 된다.

내가 선택한 셀 또는 영역이 target이 된다. 이문제에서 각 헤드에서 더블 클릭을 하게되면 그 헤드 전체가 영역에 속하기 때문에  선택한 셀, 즉 Target의 전체 열에서 전체영역과의 교집합을 구하면 전체영역에 속한 해당 열만 선택되게 된다.

Set rngU = Intersect(Target.EntireColumn, rngAll)
        
Set rngM = Intersect(rngU.SpecialCells(2).EntireRow, rngAll)

선택된 열에서 값이 있는 셀들의 전체 행을 구하고 그것의 교집합을 구하면 전체 영역에서 값들이 있는 영역들만 잡히게 된다.

본인의  셀기반으로 늘어놓은 코드들을 보면 이 개념이 많이 사용하는 것을 볼 수 있을 것이다. 나름 고급진 코드이니 공부해보길 바란다.

 

다음으로 알아볼 구문은

For Each rngA In rngAll.Rows                                   
            
    If WorksheetFunction.CountBlank(rngA) < 5 Then             
        If rngM Is Nothing Then                                

              Set rngM = rngA
        Else: Set rngM = Union(rngM, rngA)
        End If

    End If
Next rngA

전체영역을 행 단위로 FOR EACH 로 순환하는 코드를 유념하길 바란다.

행 단위로 움직이면서 이를 엑셀함수인 CountBlank 함수로 빈공간을 계산하여 5개 아닌 행들을 Union으로 계속 모아가는 코드이다.

 

다음은 공동 코드이다. 특정 영역에서 만들어진 rngM이거나 전체 영역에서 만들어진 rngM을 복사하여 전체영역에서 한행 아래에 이를 복사 붙혀넣기 하고, 전체영역을 삭제하면서 그 하위에 있는 영역을 위로 끌어오면서 마치 필터링 된거 같은 효과를 주는 것이다. 

rngM.Copy Cells(rngAll.Rows.Count, "a")(2)                 

rngAll.Delete Shift:=xlUp

이번 문제는 총 만행의 데이터를 가지고 셀 기반으로 만들어봤지만 셀계산으로 인한 딜레이가 좀 심하다. 나중에 배열을 배우고 나서 이문제를 다시한번 풀어보도록 하겠다..

그럼...이만

더보기
Option Explicit
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

    Dim rngAll As Range: Set rngAll = [a1:e10001]
    Dim rngU As Range, rngM As Range, rngA As Range

    Application.ScreenUpdating = False
    
        If Intersect(Target, [a1:f1]) Is Nothing Then Exit Sub              '= 이벤트구간
        
        If Target.Address <> "$F$1" Then                                    '= 전체가 아니면
      
            Set rngU = Intersect(Target.EntireColumn, rngAll)               '= 각 헤더의 전체열과 전제 영역사이의 교집합을 구하고
        
            Set rngM = Intersect(rngU.SpecialCells(2).EntireRow, rngAll)    '= 그중 행값이 있는 것들의 교집합을 구해서 rngM을 설정해라
            
        Else                                                                '= 전체 구간이면
 
            For Each rngA In rngAll.Rows                                    '= 전체영역을 행단위로 움직여라
            
                If WorksheetFunction.CountBlank(rngA) < 5 Then              '= 공백이 아닌 부분이 하나라고 있으면
                
                    If rngM Is Nothing Then                                 '= rngM으로 설정해라
                    
                          Set rngM = rngA
                    Else: Set rngM = Union(rngM, rngA)
                    End If
                    
                End If
            Next rngA
            
        End If
   
        rngM.Copy Cells(rngAll.Rows.Count, "a")(2)                         '= rngM을 복사해서 전체영역의 밑에다 붙혀넣어라
        rngAll.Delete Shift:=xlUp                                          '= 전체 영역을 삭제하고 셀을 위로 올려라
    
    Application.ScreenUpdating = True
    Cancel = True
End Sub

Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)  '= 오른쪽 마우스 누르시 초기화

    Application.EnableEvents = False
        Sheets("문제").[a1:e10001].Copy Sheets("실습").[a1]
    Application.EnableEvents = True
    
    Cancel = True
    
End Sub

기초방#16.xlsm
3.27MB

댓글