[엑셀 VBA 예제5] 값에 따라 셀 색깔 바꾸는 엑셀 매크로




이번 예제는 엑셀에 값을 입력할 때 마다 지정한 값에 따라서 셀 색상이 바뀌는 엑셀 매크로입니다.


[엑셀 VBA 강의 #15]에서 강의한 내용을 응용했습니다.






위와 같은 시트에서, 거래금액 란의 금액에 따라 색깔이 자동적으로 바뀌는 매크로를 만들어 보고자 합니다.


Private Sub worksheet_change(ByVal Target As Range)


Dim i As Integer

Dim n As Integer

Dim m As Integer


If Not Intersect(Range("c2:c9"), Target) Is Nothing Then

'----------------------여기부터 범위가 1보다 클 경우

If Target.Count > 1 Then            '타겟의 범위가 1보다 크다면(바뀌는 값의 범위가 한개가 아니라면)


n =  Target.Row                    '값을 수정하는 범위의 첫 행 (가장 윗행)

m = n + Target.Count - 1            '값을 수정하는 범위의 마지막 행(첫 행 + 범위 크기 - 1)


For i = n To m                            '범위의 첫 행부터 마지막 행까지 반복


    Select Case Cells(i, 3).Value            '셀의 값을 조건으로 한 조건문

    Case 0                                        '값이 0이라면(없다면)

    Cells(i, 3).Interior.color = xlNone        '셀을 투명하게(초기화)

    Case Is < 300000                            '값이 300000보다 작다면

    Cells(i, 3).Interior.color = RGB(255, 0, 0)        'red 색상으로 변경

    Case 300000 To 10000000                '값이 300000과 10000000 사이라면

    Cells(i, 3).Interior.color = RGB(0, 255, 0)        'green 색상으로 변경

    Case Is > 10000000                        '값이 10000000보다 크다면

    Cells(i, 3).Interior.color = RGB(0, 0, 255)        'blue 색상으로 변경

    End Select

Next i                    '다음 셀에서 반복


Exit Sub                '프로시져 종료

else

End If

'-------------------------여기까지 범위가 1보다 클 경우


'-------------------------여기부터 범위가 1일경우(한개의 셀만 수정할 경우)



    Select Case Target

        Case 0

        Target.Interior.color = xlNone

        Case Is < 300000

        Target.Interior.color = RGB(255, 0, 0)

        Case 300000 To 10000000

        Target.Interior.color = RGB(0, 255, 0)

        Case Is > 10000000

        Target.Interior.color = RGB(0, 0, 255)

    End Select

End If


End Sub





※ 이해가 안된다면 [엑셀 VBA #15] 강의를 읽어보세요.





Target의 범위가 무엇을 뜻하는 것인가요?


셀의 값을 수정할 경우, 일반적으로 한 개의 셀을 선택한 후 값을 집어넣지만,

복사 붙혀넣기를 통해 여러 값을 한번에 넣을 수도 있고, 셀을 드래그 블록지정 한 후 삭제를 해서 값을 없앨 수도 있습니다.


이러한 경우 Select Case Target으로 조건문을 만든다면, 타겟의 범위가 넓고, 값이 여러개이기 때문에 에러가 나게 됩니다.

따라서, Range 범위가 1일 경우와 1보다 큰 경우를 따로 설정하여 에러를 방지하기 위함입니다.


범위가 1보다 클 경우 반복문을 사용해 셀을 하나씩 읽어들이는 방법을 사용합니다.












Posted by Simon K
:

[엑셀 VBA 예제4] 기간별(날짜별) 합계 구하기



이번 예제는 기간/날짜별 합계를 구하는 예제입니다.


사업체를 운영하거나, 가계부를 작성하거나, 모종의 이유로 장부를 작성하고 있는 경우에 날짜별로 합계를 구할 필요가 있습니다.







위와 같은 장부에서, 날짜별 액수를 더하고 E1셀부터 날짜를, E2셀부터 입금액을 넣는 VBA입니다.

버튼을 누르게 되면 아래와 같은 결과를 얻을 수 있습니다.







Sub example()


Dim sumdata()                '값을 넣을 배열 추가

Dim nrow As Long            '시작하는 셀의 행

Dim ncol As Long                '시작하는 셀의 열

Dim lastD As String             

Dim i As Integer   

Dim D as string



    nrow = 2                '시작하는 셀의 행

    ncol = 1                '시작하는 셀의 열

    i = 1                    '카운터(배열의 행을 추가하기 위한)

    lastD = Left(Cells(nrow, ncol).Value, 7)        '날짜 중복을 방지하기 위한 설정

        For nrow = 2 To Cells(2, 1).End(4).Row        '시작행 2부터 값이 있는 마지막 셀까지 반복

        

        D = Cells(nrow, ncol).Value         '날짜 값 변수에 넣기               

            If D <> lastD Then                '이전 날짜 값과 같지 않다면

            i = i + 1                            '카운터에 1을 더한다

            End If

                ReDim Preserve sumdata(1 To 2, 1 To i)    '배열 재선언(카운터만큼 열을 늘린다)

                sumdata(1, i) = D                '날짜값을 배열의 첫 값에 넣음

                sumdata(2, i) = sumdata(2, i) + Cells(nrow, ncol).Offset(0, 1)   '누적되는 액수를 두번째 칸에 넣음

                lastD = D                'lastD값 재생성

        Next nrow             '날짜가 변할때 까지 액수 누적 반복       

   

    Cells(1, 4).Resize(2, i) = sumdata        '배열을 셀에 집어넣기

    


End Sub







ReDim Preserve는 무엇일까요?


Redim 배열()을 할 경우에는 배열의 값이 empty로 초기화됩니다.


하비만 Redim Preserve 배열()을 선언하는 경우에는, 배열의 칸이 작아지거나 아예 변경이 되지 않는 이상, 값이 변동되지 않습니다.






Posted by Simon K
:

[엑셀 VBA 예제3] 엑셀 색깔별 합계 구하기





이번 포스팅에선 엑셀 색깔별 합계를 구하는 예제를 살펴보겠습니다.


선택된 범위 안에서, 선택된 셀의 색깔로 칠해진 값의 합을 구하는 예제입니다.


사용하기 편하도록 Function 을 사용해서 사용자정의 함수를 만들어 보겠습니다.


예제를 받고 따라와주세요.







사용자정의 함수란?


사용자정의 함수는 엑셀에 기본으로 탑제된 함수 이외에 필요한 기능이 있을 경우, 사용자가 직접 만드는 함수를 말합니다.


일반 함수와 같이 "=함수이름(인수1,인수2,인수3......,인수N)" 의 형식으로 엑셀에서 사용할 수 있습니다.


사용자정의 함수 코드는 모듈을 생성해서 작성해야 합니다.










위와 같이 숫자가 담긴 셀에 색깔이 채워져 있을 경우, 색깔 별로 합계를 구하려고 합니다.





※ 사용자정의 함수는 시트에 코드를 짜면 안되고 꼭 모듈을 생성해서 만들어 줘야 합니다.


Public Function colorsum(rngcolor, rng As Range)   '함수 이름은 colorsum, 인수는 '지정색깔(rngcolor)', '합계범위(rng)'


Dim sum As Long  '구할 합계 sum 변수설정

Dim SearchColor as Long  '색깔 변수 설정


sum = 0  '합계 초기값 설정


SearchColor = rngcolor.Interior.color    '첫 번째 인수인 rngcolor에 지정된 셀의 색깔값을 SearchColor에 지정


For Each rngn In rng        '두 번째 인수인 rng의 범위 안에서 처음부터 끝까지 순환


If rngn.Interior.color = SearchColor Then    '해당 셀의 색깔이 rngcolor의 색깔과 같다면

sum = sum + rngn.Value            '합계에 해당 값을 더한다

End If


Next                '그 다음 셀으로 이동


colorsum = sum            '출력할 함수값 지정


End Function






코드를 작성한 후 엑셀 시트에서 일반 함수를 사용하는것처럼 값을 입력하면 색깔 별 합계를 구할 수 있습니다.


함수의 첫 번째 인수는 합할 색깔이 있는 셀을 선택하고, 두 번째 인수는 합계 범위를 지정하면 됩니다.


파란색 합계를 구하고 싶은 경우 A1를 C1으로 바꾸면 되겠죠? 





함수를 실행하면 위와 같이 값을 구할 수 있습니다.


Posted by Simon K
:


[엑셀 VBA 예제2] 여러 시트에 있는 값을 한 시트로 옮기기






이번 엑셀 VBA 예제는 여러 시트에 있는 값을 조건에 맞춰서 한 시트로 취합하는 예제입니다.

With문, For~Next문, Find문, If문, Offset문, Instr문이 사용됩니다.


예제를 받아주세요.






이번 엑셀 VBA 예제의 내용은 아래와 같습니다.





위 두 시트의 자산 총계를 아래 시트의 자산 란에 연도별로 넣고자 합니다.


2015, 2016 두 가지의 자료만 넣는 예제이지만, 시트를 추가하면 2000년부터 2099년까지 활용할 수 있는 예제입니다.




엑셀 VBA를 본격적으로 작성하기 전에 어떻게 만들것인지 구상이 필요합니다.


제 구상은 아래와 같습니다:


1.  시트1(2015년 재무재표) ~시트n(2099년 재무재표) 이름의 연도값(20xx)을 인식 및 변수로 추출

2.  년도별로 해당하는 시트에서 "자산총계" 문자가 있는 셀을 찾고, 바로 아래의 값을 변수로 추출

3.  "비교" 시트의 년도값(20xx)의 행값과 "자산"의 열값을 변수로 추출 (n, 2)

4.  (행값, 열값)셀에 각 시트의 자산총계 바로 아래에 있는 값을 넣는다

5.  마지막 시트까지 반복






이제 엑셀 VBA 코드를 보겠습니다.


COMP는 이름이 "비교"인 시트 값을 뜻합니다.


조건1. 시트의 이름에는 20을 포함하는 년도값이 한번 포함되야 합니다.

조건2. 데이타를 합하는 시트의 시트 값은 "COMP"로 설정되어 있어야 합니다.

조건3. COMP 시트를 제외한 모든 시트 값은 기본값인 Sheet1~Sheetn으로 되어있어야 합니다.

조건4. 코드는 COMP 시트에서 실행하면 안됩니다.





Option Explicit                '변수가 선언(dim) 없이 사용되는 것을 방지


Sub example()

Dim b As Object

Dim c As Object

Dim d As Object

Dim wks As Worksheet

Dim stryear As String

Dim currrow As Integer

Dim currcol As Integer

Dim curval As Long



With ActiveWorkbook                            '해당 워크북에서

    

    For Each wks In Worksheets                '모든 워크시트를 순환

    

        If InStr(wks.Name, "20") <> 0 Then            '해당 워크시트의 이름에 20이 들어가면

                                  

                 With wks.Range("a1:z20")                                    'range 범위는 모든 값을 포함하는 범위로 설정

                      Set b = .Find("자산총계", lookat:=xlWhole)            '"자산총계" 값이 있는 셀을 찾는다

                        If Not b Is Nothing Then                    '"자산총계" 값이 하나라도 있다면

                

                        curval = b.Offset(1, 0).Value                'curval(변수)는 "자산총계" 셀 바로 아래의 셀 값으로 설정

                      End If

                 End With


stryear = Mid(wks.Name, InStr(wks.Name, "20"), 4)                    'stryear(변수)는 시트 이름에 포함된 년도값(20xx)

               

    

                  With COMP.Range("a1:z20")                    'COMP 시트에서 (Range 범위는 모든 값을 포함하는 범위)

            

                  Set c = .Find(stryear, lookat:=xlPart)            'stryear값을 포함하는 셀을 찾는다.

                       If Not c Is Nothing Then                    'stryear 값을 포함하는 셀이 하나라도 있다면

                

                        currrow = c.Row                    'currrow(변수) 값은 그 셀의 행값

                

                        End If

                

                

                   Set d = .Find("자산", lookat:=xlWhole)            '"자산"을 포함하는 셀을 찾는다

                    If Not d Is Nothing Then            

                

                     currcol = d.Column                        'currcol(변수) 값은 그 셀의 열값

                

                   End If

                     

                

                  End With

        

    

COMP.Cells(currrow, currcol).Value = curval       '년도와 항목에 맞춰서 값을 집어넣는다         '


 

        End If

    Next wks                    '다음 시트로 넘어가기



End With

 

 MsgBox "입력 완료"


End Sub



파란색으로 표시한 Instr 문은 string(문자열) 내에서 해당 문자가 시작되는 위치를 찾아줍니다.


따라서 문자가 존재하지 않는 경우 0의 값을 돌려주게 됩니다.


이를 응용해서 년도값을 추출할 때에는 mid문을 사용해서 instr과 조합해서 사용할 수 있습니다.


stryear = Mid(wks.Name, InStr(wks.Name, "20"), 4)


위 코드는 시트 이름에서 20이라는 문자의 위치를 찾고, 그 위치부터 오른쪽으로 4 자리의 숫자를 추출하는 코드입니다.


2020년의 경우에도 알맞은 값을 돌려줍니다. (처음 만나는 20을 찾기 때문)









Posted by Simon K
:

[엑셀 VBA 예제1] 텍스트 파일(.txt) 엑셀에 입력하기




실무적인 엑셀 VBA에 관한 질문이 들어와서, 엑셀 VBA 기초 강의와는 별개로 실전 예제도 연재해 보려고 합니다.

익숙하지 않은 내용들이겠지만 실전 예제를 통해 공부하는 것도 큰 도움이 될 것이라 생각합니다.

같이 진행되는 엑셀 VBA 기초 강의와는 번외적인 내용으로, 진도에 맞지 않는 점 인지하여 주시기 바랍니다.




엑셀 VBA는 매우 강력한 프로그래밍 툴으로써, 외부파일과 연계도 가능합니다.


이번 포스팅은 텍스트 파일을 엑셀에 입력하는 예제를 소개해드리도록 하겠습니다.





위와 같이 열과 열이 일정한 관계를 갖고 있는 텍스트 파일의 경우, 동일한 배열으로 엑셀에 옮겨담을 수 있습니다.


위의 텍스트 파일은 열 간의 간격이 탭키로 설정되어 있지만, 콤마( , ), 세미콜론( ; ) 등 뿐만 아니라 어떠한 규칙도 그 규칙이 일정 하다면 충분히 엑셀로 옮길 수 있습니다.


이 텍스트 파일의 첫번째 줄을 제외하고 숫자부분을 열에 맞춰서 엑셀에 옮기고자 합니다.


이 명령을 실행하는 엑셀 VBA 코드는 아래와 같습니다.


Sub text_to_excel()

    Const loadf As Long = 2             '텍스트 파일 속에서 가져와야 하는 시작하는 행 위치

    Const loadt As Long = 99999            '텍스트 파일 속에서 가져와야 하는 마지막 행 위치보다 큰 값을 설정

    Dim strFileName As String              '텍스트 파일 이름 설정

    Dim objText As Object           '텍스트 문서 값 개체변수

    Dim i As Long                       '변하는 행값 변수

    Dim varValue As Variant           '엑셀에 입력되는 값

    

    

    

    Application.ScreenUpdating = False


    With Application.FileDialog(msoFileDialogFilePicker)

                             .Show              '파일피커 열기

        If .SelectedItems.Count = 0 Then        '아무것도 선택되지 않았을 경우 프로시저 종료

            Exit Sub

        Else

            strFileName = .SelectedItems(1)        '파일 이름 지정

        End If

    End With

    

    If Len(strFileName) > 0 Then                   '파일 이름의 길이가 0보다 크면 (파일이 존재하면)

        

        Set objText = CreateObject("Scripting.FileSystemObject").OpenTextFile(strFileName, _

        IOMode:=1, Create:=False, Format:=-2)           '지정된 이름의 파일을 열기

        

        For i = 1 To loadt                      '지정한 행 수 만큼 반복하기

            If Not objText.AtEndOfStream Then           '텍스트파일의 끝이 아니라면

            If i < loadf Then                            '행의 위치가 지정된 시작 행(loadf)보다 작다면

            objText.skipline                            '그 행을 뛰어 넘는다

            Else

                varValue = Split(objText.ReadLine, vbTab)         '텍스트파일의 한 행의 값을 탭으로 분리해서 가져온다    

'vbTab을 "," ";" " " 등으로 바꿔서 사용할 수 있다.

                Cells(Rows.Count, 1).End(3)(2).Resize(, UBound(varValue) + 1) = varValue        '셀에 텍스트파일 값을 넣기                  

            End If

            End If

        Next i

    End If

       objText.Close

    Set objText = Nothing

    

End Sub



위 엑셀 vba 프로시저를 끝낸 후 엑셀에 출력되는 값은 아래와 같습니다.




만약에 특정 열의 값만 추출하고 싶다면 파란색으로 표시된 varValue 를 varValue(숫자) 로 바꿔주시고, 주황색으로 표시된 UBound(varValue)+1 부분을 1로 바꿔주시면 됩니다.   


varValue의 숫자값은 0부터 시작하는 정수가 되어야 합니다.


예를 들자면, varValue(1)는 2번째 열만 가져오게 됩니다.


이러한 방법을 통해서 텍스트 파일을 엑셀으로 옮겨올 수 있습니다.





그냥 넘어가긴 아쉬우니 제가 엑셀 VBA에서 자주 쓰는 간단한 편법을 하나 공개하도록 하겠습니다.


엑셀 VBA에서는 Worksheetfunction을 사용해서 엑셀 고유의 함수 기능을 구현할 수 있습니다.


하지만 Worksheetfunction을 굳이 사용하지 않고 엑셀 함수를 적용할 수 있는 방법 또한 존재합니다.


예를 들어 텍스트 파일의 2번째 열만 추출해서 평균값을 "E2"셀에 넣고, 평균값을 제외한 모든 값을 삭제해 보겠습니다.


Sub text_to_excel()

    Const loadf As Long = 2             '텍스트 파일 속에서 가져와야 하는 시작하는 행 위치

    Const loadt As Long = 99999            '텍스트 파일 속에서 가져와야 하는 마지막 행 위치보다 큰 값을 설정

    Dim strFileName As String              '텍스트 파일 이름 설정

    Dim objText As Object           '텍스트 문서 값 개체변수

    Dim i As Long                       '변하는 행값 변수

    Dim varValue As Variant           '엑셀에 입력되는 값

    

    

    

    Application.ScreenUpdating = False


    With Application.FileDialog(msoFileDialogFilePicker)

                             .Show              '파일피커 열기

        If .SelectedItems.Count = 0 Then        '아무것도 선택되지 않았을 경우 프로시저 종료

            Exit Sub

        Else

            strFileName = .SelectedItems(1)        '파일 이름 지정

        End If

    End With

    

    If Len(strFileName) > 0 Then                   '파일 이름의 길이가 0보다 크면 (파일이 존재하면)

        

        Set objText = CreateObject("Scripting.FileSystemObject").OpenTextFile(strFileName, _

        IOMode:=1, Create:=False, Format:=-2)           '지정된 이름의 파일을 열기

        

        For i = 1 To loadt                      '지정한 행 수 만큼 반복하기

            If Not objText.AtEndOfStream Then           '텍스트파일의 끝이 아니라면

            If i < loadf Then

            objText.skipline

            Else

                varValue = Split(objText.ReadLine, vbTab)         '텍스트파일의 한 행의 값을 탭으로 분리해서 가져온다

                Cells(Rows.Count, 1).End(3)(2).Resize(, 1) = varValue(1)        '셀에 텍스트파일 값을 넣기      '

            End If

            End If

        Next i

    End If

        objText.Close

  '(a2:a99999) 값은 평균 낼 데이터를 포함하는 범위

        Cells(2, 5).value = "=average(a2:a99999)"                'average 함수식을 셀(E5)에 집어넣는다

        Cells(2, 5).value = Cells(2, 5).value                         '출력된 함수값을 일반 형식의 값으로 바꾼다.

        Range("a2:a99999").Value = ""                                 '텍스트파일에서 추출한 데이터를 삭제한다

    Set objText = Nothing

    

End Sub


초록색으로 표시된 부분이 추가된 부분입니다.


특정 셀에 함수식을 넣는 것만으로 함수식의 결과값을 얻어낼 수 있습니다.


average 함수 뿐만 아니라 엑셀의 모든 함수를 사용할 수 있습니다.


하지만 편법이다 보니 광범위하게 사용하기는 힘듭니다.


이런 방법도 있구나.. 하고 알아두시면 됩니다.


Worksheetfunction에 대한 내용은 추후에 엑셀 기초강의에서 다루도록 하겠습니다.











Posted by Simon K
: