'vba는 Visual Basic for Applicaion으로,
'ms오피스나 cad 등의 application에서 VB를 사용하여 업무를 자동화할 수 있도록 한 것

'엑셀에서 버튼 등 클릭할 것을 작도한 후, 우클릭->매크로지정->새로만들기 를 통해 클릭 이벤트에 대한 코드를 작성할 수 있다.
'각 이벤트와 함수들을 대체로 module이나 각 개체 내부에 주요 기능별로 구분하여 코드를 작성한다.
'alt+F11 단축키로 코드 편집 화면으로 진입한다.
'코드에 암호를 걸어 코드 보안을 유지 할 수 있다.
'암호를 모르면 코드를 볼 수 없다. 
'VBAProject 우클릭 -> VBAProject 속성 -> 보호 탭 -> "읽기 전용으로 프로젝트 잠금" 체크, 암호 입력/지정
'xlsm(매크로 전용) 확장자로 저장해야 매크로를 함께 저장할 수 있다.
'파일 오픈 시, 상단의 컨텐츠 사용 메세지을 클릭/허용해야 코드가 동작할 수 있다.

'문법은 Visual Basic의 예전 방식에 따른다.
'작은 따옴표로 주석 처리한다.

'----------------------------------------------------------------------------------

'vb에서는 변수를 선언하지 않고 사용하여도(묵시적 선언) 에러가 발생하지 않는데, 아래와 같이 선언하여 이를 방지할 수 있다.
Option Explicit
'복잡한 코드를 작성할 경우에는 Option Explicit를 코드의 최상단에 선언하여
'변수가 사용되기 전에 반드시 선언되어야(명시적 선언) 함을 엄격히 하는 것이 좋음

'----------------------------------------------------------------------------------

'엑셀 데이타 접근
Worksheets("Sheet1").Range("A1").Value = "Hello, World!" '시트의 이름이 바뀌면 안됨, 오동작/에러
Worksheets(1).Range("A1").Value = "Hello, World!" '시트의 순서가 바뀌면 안됨, 오동작/에러
Worksheets("Sheet1").Cells(1, 1).Value = "Hello, World!" '시트의 이름이 바뀌면 안됨, 오동작/에러
Worksheets(1).Cells(1, 1).Value = "Hello, World!" '시트의 순서가 바뀌면 안됨, 오동작/에러
'Cells(행,열)

'지정 영역이나 셀에 이름을 부여하여 용이하게 접근할 수도 있다.
' 셀에 이름 지정하기
Range("A1").Name = "MyCell"
' 영역에 이름 지정하기
Range("A1:B10").Name = "MyRange"

myValue = Range("MyCell").Value

'----------------------------------------------------------------------------------

'변수 선언
'global, local 변수 구분 요망
Public 변수명 As String ' 추천 방식, global 변수, module의 상단에 선언
Global 변수명 As String ' global 변수, module의 상단에 선언
module에 선언한 함수와 위와 같이 module 상단에 선언한 변수는 다른 module에서도 접근할 수 있다.

Dim i As Integer
i = 1 '숫자는 따옴표 없이

Dim str As String
str = "test" '문자는 큰따옴표로 감싸기

Dim val1 As Long
Dim val2 As Double

Dim fname As Variant '변수라는 것만 선언하고, 타입 미지정. 
'나중에 변수값이 할당될 때 해당 변수의 타입으로 자동 형변환되며 타입이 정의되는 것
'잦은 형변환은 성능과 연관이 있으므로, 복잡한 코드에서는 과용하는 것을 추천하지 않는다.

Dim obj As Object '개체(셀, 범위, 통합문서 등)를 담음

Dim strArr(100) As String '배열
Dim strArr2() As String '배열
ReDim strArr2(500) ' 배열 크기 재설정, 기존의 데이타는 초기화 되므로 필요시 백업 필요

Public PanelArray As Variant
PanelArray = Array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m")

'사용자 정의 타입(c/java의 struct와 비슷)
'연관된 변수들을 묶어서 관리하기 편리함
Type Person
    Name As String
    Age As Integer
    Height As Double
End Type

Dim p As Person
p.Name = "John"
p.Age = 30
p.Height = 175.5

'----------------------------------------------------------------------------------

'변수/함수로의 접근 가능 영역

'변수
'최상단에 public/global로 명시한 변수는 어디에서나 접근 가능함
'그 외 변수는 아래와 같이 접근 가능한 영역이 한정된다.(local 변수)
Dim a as String 'a : 다른 module에서는 접근 불가
Sub test()
a = "hello" 
Dim b as String 'b : 선언한 위치의 함수를 벗어나면 접근 불가
b = "world"
If a = "hello" Then
Dim c as String 'c : 선언한 위치의 블럭(if문)을 벗어나면 접근 불가
c = "vba"
Msgbox a & b & c '에러 없음
End If
Msgbox a & b & c 'c 변수에 접근 불가, 에러 발생, 오동작
End Sub
'이러한 local 변수의 접근 가능 영역 개념은 대부분의 개발언어에서 동일하다.

'함수
'함수는 module에 선언하면 어디에서나 접근 가능한 함수가 됨

'----------------------------------------------------------------------------------

'형변환
Dim num As Integer
Dim str As String
str = "11"
num = CInt(str) '명시적, 문자로 변환할 때에는 CStr() 사용
MsgBox num
    
num = str '묵시적
MsgBox num

'----------------------------------------------------------------------------------

'예외 처리
'goto는 해당 지점으로 모든 과정을 생략하고 바로 이동하는 것으로, 최대한 사용하지 않는 것을 권장한다.
On Error GoTo ErrHandler
'코드의 마지막에 선언하면서 Exit Sub 혹은 Exit Function 등을 바로 앞에 동반 선언해야 한다.
'에러가 있을 때에만 에러 처리 구문으로 진입하게 하기 위함이다.
Exit Sub
ErrHandler:
MsgBox ("오류!")

'----------------------------------------------------------------------------------

'함수 선언
'return이 없는 형태
Sub 함수명()
End Sub

'return이 있는 형태
Function testFunc() As 타입
testFunc = "test" '함수명에 할당하면 return된다.
End Function

'call by value
Function testFunc(num As Integer) As String
num = num + 1 '본 함수 내의 num만 증가될 뿐
testFunc = "ok"
End Function

Function testFunc(ByVal num As Integer) As String
num = num + 1 '본 함수 내의 num만 증가될 뿐
testFunc = "ok"
End Function

'call by reference
Function testFunc(ByRef num As Integer) As String
num = num + 1 '본 함수를 호출한 곳의 변수 값을 1 증가시키는 것이다. 포인터와 같이 주소를 참조하였기 때문에.
testFunc = "ok"
End Function

'다른 사람이 작성한 코드를 분석할 때
'사용자 정의 변수/함수인지, vba에서 제공되는 것인지 확인 할 때
'또는 사용자 정의 변수/함수의 정의된 곳으로 바로가기하고 싶을 때
'변수나 함수명을 드래그 -> 우클릭 -> 정의 선택 
'-> 직접 선언한 것은 해당 위치로 자동 이동되고, vba에서 제공되는 것은 라이브러리로 이동함

'함수 호출, 사용하기
testFunc num 'return 없는 경우는 괄호없이 띄어쓰기만 한다.
testFunc num, num1, num2 '파라미터가 여러 개일 경우는, 콤마로 구분한다.
data = testFunc(num) 'return 받아 전달할 때에는 괄호로 감싸준다.

'----------------------------------------------------------------------------------

'조건문
If num = 1 AND num1 <> 1 AND num2 >= 1 Then 'equal 문자(=)는 하나만 써야 된다.(== 비허용)
MsgBox("test1") ' <>는 같지 않음을 표현
ElseIf num = 2 Then
MsgBox("test2")
Else
MsgBox("test3")
End If

If Not num = 1 Then 'If Not 가능
    MsgBox("test3")
End If

Select Case expression
    Case 1:
        ' 1에 대한 처리
    Case 2:
        ' 2에 대한 처리
    Case Else
        ' 모든 조건에 해당하지 않는 경우 처리
End Select

'----------------------------------------------------------------------------------

'반복문
For i = 1 To 10
    Worksheets("Sheet1").Range("A" & i).Value = "Hello, World! " & i
Next i

Do While i < 100
    Worksheets("Sheet1").Range("A" & i).Value = "Hello, World! " & i
i = i + 1
Loop
'예시
Do While (Worksheets("Sheet1").Cells(i, 1).Value <> "")
    Worksheets("Sheet1").Cells(i, 1).Value = ""
    i = i + 1
Loop

While i < 100
    Worksheets("Sheet1").Range("A" & i).Value = "Hello, World! " & i
i = i + 1
Wend

Do Until i >= 100
    Worksheets("Sheet1").Range("A" & i).Value = "Hello, World! " & i
i = i + 1
Loop

For Each str In strArr
    Worksheets("Sheet1").Range("A" & i).Value = str
i = i + 1
Next item

'반복문을 즉시 빠져나갈 때에는 Exit 사용
Exit Do
Exit For
Exit While

For i = 1 To 10
    Worksheets("Sheet1").Range("A" & i).Value = "Hello, World! " & i
If i >= 5 Then
Exit For
End If
Next i

'아래와 같이 반복 조건 없이 복잡한 로직 중간에 exit를 통해 빠져나가도록 하는 경우도 있는데,  
'코드 가독성이 떨어져서 보기에는 좋지 않은 것 같음
Do
'로직 구현
If Area = "" Or i > 10000 Then Exit Do
'로직 구현
i = i + 1
Loop

'예시
Dim wS As Worksheet
For Each wS In Worksheets
    If wS.Name = "결과" Or wS.Name = "rawdata" Then
        wS.Select
        Cells.Clear
    End If
    If wS.Name = "rawdata" Then
        wS.Cells(1, 1).Value = "PATH"
        wS.Cells(1, 2).Value = "TAG"
        wS.Cells(1, 3).Value = "PJT_ID"
        wS.Cells(1, 4).Value = "PATHTAG"
        wS.Cells(1, 5).Value = "SYMBOL"
    End If
Next

'----------------------------------------------------------------------------------

'많이 쓰는 문자열 처리 함수
loc = InStr(1, "abcdefg", "cd") 'loc에 3이 전달됨
'InStr() : 특정 문자열 찾아 위치를 가져옴
'Instr(검색시작위치,전체문자열,검색문자)

loc = InStrRev("abcdefgabcde", "cd") 'loc에 10이 전달됨
'InStrRev() : 특정 문자열을 역순으로 찾아 위치를 가져옴
'InStrRev(전체문자열,검색문자)

txt = Mid("abcdefg", 3, 2) 'txt에 "cd"가 전달됨
'Mid() : 문자열의 중간부분을 잘라내어 가져옴
'Mid(전체문자열,시작위치,[잘라낼길이])

txt = Replace("abcdefg", "cd", "dc") 'txt에 "abdcefg"가 전달됨
'Replace() : 지정 문자열을 다른 지정 문자열로 변경함
'Replace(전체문자열,변경전문자,변경후문자)

size = Len("abcdefg") 'size에 7 전달됨
'Len() : 문자열 길이 가져옴
'Len(전체문자열)

txt = Left("abcdefg", 3) 'txt에 "abc"가 전달됨 
'Left() : 왼쪽부터 지정 갯수만큼의 문자열 가져옴
'Left(전체문자열,가져올길이)

txt = Right("abcdefg", 3) 'txt에 "efg"가 전달됨 
'Right() : 오른쪽부터 지정 갯수만큼의 문자열 가져옴
'Right(전체문자열,가져올길이)

txt = Trim(" abc def ") 'txt에 "abc def"가 전달됨 
'Trim() : 문자열의 앞뒤 공백 제거
'Trim(전체문자열)

txt = LCase("AbcD") 'txt에 "abcd"가 전달됨 
'LCase() : 소문자로 변환
'LCase(전체문자열)

txt = UCase("AbcD") 'txt에 "ABCD"가 전달됨 
'UCase() : 대문자로 변환
'UCase(전체문자열)

txt = Split("a:b:c:d", ":") '배열 txt에 4개의 문자가 분리되어 전달됨. txt(0)에 "a"가 전달 
'Split() : 특정 문자를 기준으로 문자열을 분해하여 배열로 가져옴
'Split(전체문자열,구획문자)

Chr() ' 특정 문자를 가져옴(ASCII 문자 코드나 유니코드 문자 코드), ASCII 코드를 검색하면 매핑되는 숫자를 알 수 있음
Chr(34) '큰따옴표

'예약된 문자열 변수
vbCrLf : 새 줄 문자(새 줄과 다음 줄의 시작 부분)
vbNewLine : vbCrLf과 비슷
'vbCrLf은 Carriage Return과 Line Feed 두 문자를 모두 나타내는 반면, 
'vbNewLine은 각각의 운영체제에서 사용하는 새 줄 문자를 반환 
'즉, vbNewLine은 운영체제에 상관없이 동작하는 코드를 작성할 때 유용
vbTab: 탭 문자(수평 탭 간격)

'----------------------------------------------------------------------------------

'동작 중 응답없음 방지
'긴 작업이나 루프에서 호출되며, 이를 통해 다른 애플리케이션의 입력을 처리하고, UI의 응답성을 유지
'코드 실행을 일시 중단하고, 컨트롤을 Windows 운영 체제에 넘기므로, 코드 성능이 저하될 수 있음
'필요한 경우에만 사용하는 것이 좋음
'예를 들어, dpl 파일 생성 툴 사용 중, 응답없음 상태가 되는 것을 막을 수 있으나, 
'처리량이 많을 경우 반복문 사이에서 지속적으로 운영 체제에 응답해야 하므로 코드 동작 완료까지의 시간이 상당히 지연될 수 있다.
'필요시에는 반복문이 2,3중, 또는 그 이상 겹쳐있다면, 가능하면 최대한 외곽의 반복문에 두는 것이 좋다.  
DoEvents

'----------------------------------------------------------------------------------

'파일 경로
Dim dirPath, sPathInfo As String
dirPath = ActiveWorkbook.path & "\DATA\"
sPathInfo = Dir(dirPath, vbDirectory) 'Dir 함수로 해당 경로에 파일/디렉토리가 존재하는지 체크 가능
If sPathInfo = "" Then
    MkDir dirPath
End If

'----------------------------------------------------------------------------------

'외부 파일에 쓰기
Dim myFile As Integer
myFile = FreeFile

'쓰기 전용으로 열기(For Input은 읽기 전용, For Append는 파일 끝에 이어 쓰기)
Open "C:\myFile.txt" For Output As #myFile 
'여기까지는 반복문 밖에

'Print 부분만 반복문 안에 넣는 것이 좋다. 잦은 파일 열기닫기는 성능 문제 또는 오류 발생
Print #myFile, "Hello world!"
Print #myFile, "This is a test."

'여기서부터 반복문 밖에
Close #myFile
myFile = FreeFile

'----------------------------------------------------------------------------------

'파일 삭제
Kill "C:\test.txt"

'----------------------------------------------------------------------------------

'길어진 코드 줄바꿈하기
' _를 쓰고 다음줄에 나머지 코드를 이어서 작성 가능
코드어쩌고~~~~~~~~~~~~~~~~~~~~ _
나머지코드~~~~~~

'---------------------------------------------------------------------------------------------------------------------

'폼 사용하기
'사용자 정의 폼을 추가(프로젝트 트리에서 우클릭)하여 간단한 화면을 만들수도 있다.
Private Sub UserForm1_Initialize()
    ' 폼이 로드되면 실행되는 코드
End Sub
'Initialize 외에도 다양한 이벤트에 대해 동작을 정의할 수 있다.

UserForm1.Show '디자인한 form을 화면에 띄움, 원하는 함수 내에 둠.

'----------------------------------------------------------------------------------

'디버그
'break point를 설정하면 해당 지점에서 코드는 일시 중지. 중지 시점의 변수값을 보면서 디버그에 활용할 수 있다.
'코드 각 라인 앞쪽을 클릭해서 붉은 동그라미 표시된다면, break point가 설정된 것이다. 다시 클릭하면 해제된다.
'stop을 활용하여 break point를 코드에 넣을 수도 있다. if문을 활용하여 특정 조건에서 break point 지정 가능
stop
'F5 : 전체 진행
'F8 : 코드 1줄씩 진행

'코드 내 변수를 드래그하여 조사식 창으로 드래그하면 현재값을 모니터링 가능

'----------------------------------------------------------------------------------

'변수/함수 명명 기법
'다수의 개발자, 기업이 같은 프로젝트를 협업할 때에는 코딩 스타일 표준화 필요
'1.카멜 표기법 (Camel Case)
' 첫 번째 단어는 소문자로 시작하고, 이후 단어의 첫 글자는 대문자로 적는 표기법입니다.
' 예: camelCase, numberOfApples
'2.파스칼 표기법 (Pascal Case) : 이것도 카멜 표기법이라도 부르기도 함.
' 모든 단어의 첫 글자를 대문자로 적는 표기법입니다.
' 예: PascalCase, NumberOfApples
'3.스네이크 표기법 (Snake Case) : C/Java계열, WinCC OA 표준스크립트에서 권장하는 방법
' 모든 단어를 소문자로 적고, 단어 사이를 언더바(_)로 구분하는 표기법입니다.
' 예: snake_case, number_of_apples
'4.케밥 표기법 (Kebab Case) : 하이픈(-)을 이름에 사용 가능한 웹 개발 언어 작성 시 일부 활용
' 모든 단어를 소문자로 적고, 단어 사이를 하이픈(-)으로 구분하는 표기법입니다.
' 예: kebab-case, number-of-apples

'----------------------------------------------------------------------------------

'불필요한 반복문, 조건문 등을 최소화하고, 변수와 함수를 유의미한 단어로 명명하여 사용합시다.
'하나의 표기법을 일관성 있게 따릅니다.
'들여쓰기(탭)를 해서 코드의 가독성을 높입니다.

+ Recent posts