준이로그

Sub 버튼()

Dim 제외범위주소 As String
제외범위주소 = "B2,C3" '유지하고 싶은 셀주소를 컴마로 구분하여 지정

Dim 복구리스트 As Object
Set 복구리스트 = CreateObject("Scripting.Dictionary")
복구리스트.CompareMode = 1

'복구 할 범위를 셀주소와 셀값을 구분하여 딕셔너리에 저장
For Each 값 In Split(제외범위주소, ",")
    복구리스트.Add 값, Range(값).Value
Next

'복사하기
Range("a1:c3").Value = Range("e1:g3").Value

'복구하기
For Each 키 In 복구리스트.keys
    Range(키).Value = 복구리스트(키)
Next

End Sub

배열을 컨트롤 하다 보면 데이터형식이 맞지 않아서 나오는 13 런타임 오류가 있다.

 

string 형식 배열에 integer를 넣는다거나 그 반대거나 또는 기타 데이터형식 정의가 잘못되었을 경우에 나오는 오류인데 이 부분은 정확한 데이터형식으로 정의해주거나 Variant 형식으로 정의해주면 쉽게 해결 할수 있다.

 

하지만 엑셀 내의 데이터가 아닌 외부데이터를 다이렉트로 끌어다가 배열로 넣을때 심심찮게 Null 값이 들어가는 경우가 종종 있는데 이렇게 배열에 Null 값이 들어가 있을 경우 aryData(1,2) 처럼 값에 접근 또는 기타 배열 컨트롤 함수를 쓰려 할때 역시 '13'런타임 오류가 나온다.

 

위와 같은 Null값 문제의 경우 강제로 Null 값을 vbvbNullString 으로 모두 치환 해주면 해당 오류는 쉽게 해결 가능하다.

 

다음과 같은 Funcion을 만들어 놓고 쓰면 편하다

Function 배열널값변환(배열 As Variant) As Variant

Dim i As Integer

For i = LBound(배열) To UBound(배열)
        If IsNull(배열(i)) Then 배열(i) = vbNullString
Next

배열널값변환 = 배열

End Function

2차원 배열일 경우

Function 이차원배열널값변환(배열 As Variant) As Variant

Dim i, j As Integer

For i = LBound(배열, 1) To UBound(배열, 1)
    For j = LBound(배열, 2) To UBound(배열, 2)
        If IsNull(배열(i, j)) Then 배열(i, j) = vbNullString
    Next
Next

이차원배열널값변환 = 배열

End Function

 

예제

Sub 오류코드()

Dim aryData As Variant

'어떤 외부데이터의 배열을 변수에 넣었을 때
aryData = 외부데이터배열

'이상할것 없는 코드인데 이 부분에서 13 런타임 오류가 날 경우
Debug.Print aryData(1, 2)

'위에 만들어둔 Function을 사용하여 Null값을 VBA가 인식할수 있는 형식으로 변환해준다
aryData = 이차원배열널값변환(외부데이터배열)

'그러면 13 런타임 오류가 해결 될 것이다.
Debug.Print aryData(1, 2)

End Sub

매크로기록을 하게 되면 선택하는(마우스 클릭 등) 모든 대상이 불필요하게 select / selection 으로 잡히게 됩니다.

작업대상을 바로 지정할수 있다는 것을 알고 계시면 지금보다 코딩하기가 보다 수월해지실겁니다.

1. 작업대상을 선택
2. 선택한 대상을 작업

위처럼 두 단계가 아닌

1. 대상에 대한 작업

이 되게끔 코딩하시면 됩니다.

 

예를들어 매크로기록으로 차트안의 특정영역을 변경시

ActiveChart.PlotArea.Select
Selection.Top = 0.21
Selection.Height = 210

위와 같이 코드가 쓰여지게 됩니다.

 

 

따라서 위 차트 예시의 경우 불필요하게 쓰여진 select / selection 제거하여 다음처럼 코딩을 해 볼수 있습니다.

'▼다음과 같이 단축할수 있죠
ActiveChart.PlotArea.Top = 0.21
ActiveChart.PlotArea.Height = 210

'▼with를 사용하여 이렇게도 쓸수 있습니다.
With ActiveChart.PlotArea
    .Top = 0.21
    .Height = 210
End With

'▼개체변수를 선언하여 변수를 이용하여 작업하셔도 되구요
Dim pArea As PlotArea
Set pArea = ActiveChart.PlotArea

With pArea
    .Top = 0.21
    .Height = 210
End With

'▼해당 차트의 이름을 이용하여 활성화된 차트가아닌 특정 차트를 바로 접근하여 작업하셔도 됩니다.
Dim pArea As PlotArea
Set pArea = Sheet1.ChartObjects("차트 1").Chart.PlotArea

With pArea
    .Top = 0.21
    .Height = 210
End With

셀의 값중 일부를 바꾸거나 지우려면

Dim 셀 As Range
셀.Replace "대상문자", "바뀔문자" '바꾸기
셀.Replace "대상문자", "" '지우기

 

string 문자열의 일부를 바꾸거나 지우려면

Dim 문자열 As String
문자열 = Replace(문자열, "대상문자", "바뀔문자") '바꾸기
문자열 = Replace(문자열, "대상문자", "") '지우기

 

선택 범위 내에 ★만 지우기

Sub vba포함문자지우기()

Call 별_만_지우기(Selection)

End Sub




Function 별_만_지우기(적용범위 As Range)

Dim 셀 As Range

For Each 셀 In 적용범위
    If InStr(셀.Value, "★") > 0 Then
        셀.Replace "★", ""
    End If
Next

End Function

선택 범위 내에 ★만 지우기

 

선택 범위 내에 ★이 들어간 모든 셀 지우기

Sub vba포함문자지우기()

Call 별이들어간_모든셀_지우기(Selection)

End Sub




Function 별이들어간_모든셀_지우기(적용범위 As Range)

Dim 셀 As Range

For Each 셀 In 적용범위
    If InStr(셀.Value, "★") > 0 Then
        셀.Clear
    End If
Next

End Function

선택 범위 내에 ★이 들어간 모든 셀 지우기

 

선택 범위 내에 ★이 들어간 모든 행 지우기

Sub vba포함문자지우기()

Call 별이들어간모든_행_지우기(Selection)

End Sub




Function 별이들어간모든_행_지우기(적용범위 As Range)

Dim 셀 As Range
Dim 지울셀 As Range
Set 지울셀 = Nothing

For Each 셀 In 적용범위
    If InStr(셀.Value, "★") > 0 Then
        If 지울셀 Is Nothing Then
            Set 지울셀 = 셀
        Else
            Set 지울셀 = Union(지울셀, 셀)
        End If
    End If
Next

If Not 지울셀 Is Nothing Then
    지울셀.EntireRow.Delete
End If

End Function

선택 범위 내에 ★이 들어간 모든 행 지우기

tot라는 문자가 포함된 셀의 모든 행을 지우고 싶을 때 다음과 같이 접근하면 좋다.

'b열에서 "tot"가 포함된 셀을 찾아 EntireRow로 해당 행을 대상으로
With ActiveSheet.Range("b:b").Find("tot").EntireRow
    .Interior.Color = RGB(255, 111, 111) '실수를 방지하기 위해 배경색 잠시 하이라이트
    If MsgBox("이거 지울꺼야?", vbYesNo) = vbYes Then '예를 선택하면
        .Delete '행 삭제
    Else    '아닐경우
        .Interior.Color = xlNone '배경색만 해제
    End If
End With

그러면 다음과 같이 행을 삭제 할수 있게 된다.

예를 눌러서 삭제
아니오를 눌러서 취소

 

 

평소에는 위 처럼 클릭한 곳 기준으로 선택이 됩니다.

 

다음 코드를 추가하고

Private Sub txtAB_GotFocus() 'txtAB 는 텍스트박스 컨트롤 이름입니다. 변경해서 써주세요
        With txtAB
            .SelStart = 0
            .SelLength = Len(.Text)
        End With
End Sub

다시 텍스트박스를 선택해보면

위와 같이 클릭시 텍스트박스 안의 전체 텍스트를 선택하게 됩니다.

커스텀 단축키 설정하기

1. 메뉴바 오른쪽 클릭

2. 사용자 지정 선택

3. 단축키를 설정하고 싶은 아이콘 오른쪽 클릭

4. 이름(N) 옆의 텍스트를 "alt+&x" 로 변경(원하는 단축키 조합으로 변경)

5. "기본스타일"을 "이미지 및 텍스트"로 변경

 


1. 메뉴바 오른쪽 클릭

2. 사용자 지정 선택

3. 단축키를 설정하고 싶은 아이콘 오른쪽 클릭

4. 이름(N) 옆의 텍스트를 "alt+&x" 로 변경(원하는 단축키 조합으로 변경)

5. "기본스타일"을 "이미지 및 텍스트"로 변경

닫기 버튼을 눌러 사용자 지정을 종료하면 이제 해당 메뉴를 지정된 단축키로 실행 가능합니다.

테이블 범위의 마지막 행 바로 밑의 셀 범위를 선택하면 새 행이 추가되는 코드입니다.


코드는 근본적으로 어떻게 동작하는가 관찰하기 쉽게 거의 그대로 넣었기 때문에 보기쉽게 정리되어 있지는 않습니다.

개개인의 환경에 따라서 변경 및 응용하여 사용하시기 바랍니다.


worksheet에서 선택한 셀의 위치를 기준으로 코드를 실행합니다.

테이블(listobject) 범위 외에 다른 셀을 클릭하면 값이 아예 없는 모든 행을 삭제하는 del_emptyrow를 실행합니다.

Private Sub Worksheet_SelectionChange(ByVal Target As Range) 
'테이블 마지막 행 바로 밑의 셀 범위를 선택하면 새 행 추가 
If Target.Count = 1 And Not Intersect(Target, ListObjects(1).HeaderRowRange.Offset(ListObjects(1).ListColumns(1).Range.Count)) Is Nothing Then 
    With ListObjects(1).ListRows.Add 
        '새 행을 추가하면서 실행할 코드가 있으면 여기에 작성합니다 
    End With 
'테이블을 벗어나면 값이 없는 행 삭제 
ElseIf Intersect(Target, ListObjects(1).DataBodyRange) Is Nothing Then 
    Call del_emptyrow '값이 없는 빈 행을 삭제하는 function 입니다.
End If 

End Sub

 

Function del_emptyrow() 

Dim emptyrows As Range 
Dim a As Range 
'테이블 전체 범위를 행 단위로 루프를 돌려서 빈 행만 삭제 
For Each a In ListObjects(1).ListColumns(1).DataBodyRange 
    If emptyrows Is Nothing And WorksheetFunction.CountA(Intersect(ListObjects(1).DataBodyRange, a.EntireRow)) = 0 Then 
        Set emptyrows = Intersect(ListObjects(1).DataBodyRange, a.EntireRow) 
    ElseIf Not emptyrows Is Nothing And WorksheetFunction.CountA(Intersect(ListObjects(1).DataBodyRange, a.EntireRow)) = 0 Then 
        Set emptyrows = Union(emptyrows, Intersect(ListObjects(1).DataBodyRange, a.EntireRow)) 
    End If 
Next 

If Not emptyrows Is Nothing Then emptyrows.Delete 

End Function