VBA
VBA(Visual Basic for Applications)는 Microsoft에서 제공하는 프로그래밍 언어로, 주로 Microsoft Office 제품군(예: Excel, Word, PowerPoint, Access)에서 매크로를 작성하는 데 사용됩니다. VBA를 활용하면 반복 작업을 자동화하고, 각 애플리케이션에 사용자 정의 기능을 추가할 수 있습니다.
VBA의 주요 특징과 활용 목적은 다음과 같습니다.
- 프로그래밍 언어: VBA는 Visual Basic을 기반으로 하며, 프로그래밍 언어의 기본 기능을 지원합니다. 이를 통해 조건문, 반복문, 변수, 함수, 객체, 클래스, 모듈 등을 활용하여 코드를 작성할 수 있습니다.
- 자동화: VBA는 반복적인 작업을 자동화할 수 있습니다. 예를 들어, Excel에서 워크시트 데이터를 처리하거나 특정 조건에 따라 문서를 생성하는 작업 등에 활용됩니다.
- 사용자 정의 함수 및 매크로: 사용자는 VBA로 사용자 정의 함수와 매크로를 만들 수 있습니다. 이는 기존 애플리케이션의 기능을 확장하거나 특정 요구사항에 맞는 솔루션을 구현하는 데 유용합니다.
- 이벤트 처리: VBA는 애플리케이션에서 발생하는 이벤트(예: 버튼 클릭, 시트 변경)를 처리할 수 있어, 상호작용이 가능하고 반응형으로 동작하는 애플리케이션을 만들 수 있습니다.
- 매크로 기록: 일상적인 작업을 기록하여 VBA 코드를 자동으로 생성할 수 있으며, 생성된 코드를 편집하는 것도 가능합니다. 이를 통해 빠르게 코드를 작성할 수 있습니다.
- Access 데이터베이스 프로그래밍: VBA는 Microsoft Access와 같은 애플리케이션에서 데이터베이스와 연동하는 기능을 제공합니다.
VBA를 사용하려면 각 Microsoft Office 애플리케이션에 내장된 VBA 편집기를 이용해 코드를 작성하고 실행합니다. VBA는 업무 프로세스 자동화, 보고서 생성, 데이터 처리, 사용자 정의 폼 및 함수 구현 등 다양한 작업에 활용됩니다. 강력한 도구이지만, VBA로 작업할 때는 코드 작성과 디버깅에 익숙해질 필요가 있습니다.
Welcome to VBA
MS Office 제품에서 VBA에 접근하려면 ALT+F11을 누르거나, "Developer" 탭으로 이동합니다. VBA에서 REST API 요청을 보내기 위해 별도의 설치 과정은 필요하지 않습니다.
VBA에서 JSON 다루기
VBA(Visual Basic for Applications)에서 JSON 데이터를 처리하려면 일반적으로 외부 라이브러리의 도움이 필요합니다. VBA 자체에는 JSON을 처리하기 위한 기본 함수나 라이브러리가 포함되어 있지 않습니다. 따라서 JSON 처리를 위해 'VBA-JSON'과 같은 라이브러리를 활용할 수 있습니다. 아래에서는 VBA에서 JSON 데이터를 처리하는 방법을 안내합니다.
- VBA-JSON 라이브러리 설치: VBA-JSON 라이브러리는 JSON 데이터를 파싱하고 생성하는 기능을 제공합니다. 먼저 해당 라이브러리를 다운로드하여 설치해야 합니다. VBA-JSON은 GitHub에서 제공되며, JsonConverter.bas 파일을 다운로드한 후 VBA 프로젝트에 추가할 수 있습니다. GitHub - VBA-tools/VBA-JSON: JSON conversion and parsing for VBA
-
VBA 프로젝트에 라이브러리 추가: VBA-JSON의 JsonConverter.bas 파일을 VBA 프로젝트에 추가하려면 다음 단계를 따르세요.
- VBA 프로젝트를 열고 'Module' 탭을 선택합니다.
- "File" 메뉴를 선택한 뒤 "Import File"을 클릭합니다.
- 가져올 파일로 JsonConverter.bas 파일을 선택하여 불러옵니다.
-
VBA 참조(Reference) 추가: JsonConverter.bas 파일을 사용하기 위해서는 VBA의 Dictionary 자료형을 Early binding 방식으로 사용해야 합니다. 이를 위해 "Microsoft Scripting Runtime" 참조를 추가해야 합니다.
다음 단계를 진행합니다.
- Tools 메뉴에서 References를 실행합니다.
- "Microsoft Scripting Runtime"을 찾아 체크한 후, "OK"를 클릭합니다.
VBA - JSON
- JSON 데이터 파싱
설치한 라이브러리의 ParseJson 함수를 사용하여 VBA에서 JSON 데이터를 파싱할 수 있습니다. 아래는 JSON 데이터를 파싱하는 예제입니다.
Option Explicit
Sub jsonParsing()
'JSON 문자열을 파싱하여 VBA 데이터로 변환
Dim jsonData As String
Dim data As Scripting.Dictionary
jsonData = "{""name"": ""John"", ""age"": 30, ""city"": ""New York""}"
Set data = JsonConverter.ParseJson(jsonData)
'결과 출력
Debug.Print data("name") 'John
End Sub
- JSON 데이터 생성
VBA 데이터를 JSON으로 변환하려면 ConvertToJson 함수를 사용할 수 있습니다. 아래는 VBA Dictionary를 JSON 문자열로 변환하는 예제입니다.
Option Explicit
Sub jsonParsing()
'VBA Dictionary를 JSON 문자열로 변환
Dim jsonData As String
Dim data As Scripting.Dictionary
Set data = New Dictionary
data.Add "name", "John"
data.Add "age", 30
data.Add "city", "New York"
jsonData = JsonConverter.ConvertToJson(data)
'결과 출력
Debug.Print (jsonData) '{"name":"John","age":30,"city":"New York"}
End Sub
실습 예제
VBA를 사용하여 직사각형 단면을 갖는 단순보를 생성하는 예제를 진행해 보겠습니다.
VBA의 특성을 고려하여, 본 예제에서는 Excel 시트를 활용합니다.
- 먼저, 시트에 변수를 입력할 수 있는 입력 창을 구성합니다.
- REST API 요청을 함수로 생성합니다.
Option Explicit
Function WebRequest(Method As String, Command As String, Body As String) As String
Dim TCRequestItem As Object
Dim baseURL As String
Dim URL As String
Dim MAPI_Key As Variant
Set TCRequestItem = CreateObject("WinHttp.WinHttpRequest.5.1")
'SetTimeouts(resolveTimeout, ConnectTimeout, SendTimeout, ReceiveTimeout)
TCRequestItem.SetTimeouts 200000, 200000, 200000, 200000
baseURL = Cells(2, 7).Value
MAPI_Key = Cells(3, 7).Value
URL = baseURL & Command
TCRequestItem.Open Method, URL, False
TCRequestItem.SetRequestHeader "Content-type", "application/json"
TCRequestItem.SetRequestHeader "MAPI-Key", MAPI_Key
TCRequestItem.Send Body
WebRequest = TCRequestItem.ResponseText
Debug.Print Command & " : " & TCRequestItem.Status & " - " & TCRequestItem.StatusText
End Function
- SimpleBeam을 생성하는 Sub 모듈을 작성합니다.
Sub CreateSimpleBeam()
Dim i, j, k As Integer
'input data from sheets
Dim dist As String
Dim force As String
Dim length As Double
Dim height As Double
Dim width As Double
Dim direction As String
Dim loadValue As Double
Dim modelID As Range
Dim loadCase As Range
Dim matSt As String
Dim matDB As String
dist = UCase(Cells(5, "E").Value)
force = UCase(Cells(6, "E").Value)
length = Cells(8, "E").Value
height = Cells(9, "E").Value
width = Cells(10, "E").Value
direction = Cells(9, "I").Value
loadValue = Cells(9, "J").Value
matSt = Cells(5, "J").Value
matDB = Cells(6, "J").Value
Set loadCase = Range(Cells(12, "I"), Cells(13, "J"))
Set modelID = Range(Cells(12, "E"), Cells(15, "E"))
'Dictionary
Dim dicMain As Scripting.Dictionary
Dim dicSub1 As Scripting.Dictionary
Dim dicSub2 As Scripting.Dictionary
Dim dicSub3 As Scripting.Dictionary
Dim dicSub4 As Scripting.Dictionary
Dim response As String
Dim body As String
'Create New File
response = WebRequest("POST", "/doc/new", "{}")
Debug.Print response
'Create Unit Body and Request API
Set dicMain = New Dictionary
Set dicSub1 = New Dictionary: Set dicSub2 = New Dictionary
dicSub2.Add "DIST", dist
dicSub2.Add "FORCE", force
dicSub1.Add "1", dicSub2
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("PUT", "/db/unit", body)
Debug.Print response
Set dicMain = Nothing
Set dicSub1 = Nothing: Set dicSub2 = Nothing
'Create Material Body and Request API
Set dicMain = New Dictionary: Set dicSub1 = New Dictionary
Set dicSub2 = New Dictionary: Set dicSub3 = New Dictionary
dicSub3.Add "P_TYPE", 1
dicSub3.Add "STANDARD", matSt
dicSub3.Add "DB", matDB
dicSub2.Add "TYPE", "CONC"
dicSub2.Add "NAME", matDB
dicSub2.Add "PARAM", Array(dicSub3)
dicSub1.Add modelID(1, 1), dicSub2
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("POST", "/db/matl", body)
Debug.Print response
Set dicMain = Nothing: Set dicSub1 = Nothing
Set dicSub2 = Nothing: Set dicSub3 = Nothing
'Create Section Body and Request API
Set dicMain = New Dictionary: Set dicSub1 = New Dictionary
Set dicSub2 = New Dictionary: Set dicSub3 = New Dictionary: Set dicSub4 = New Dictionary
dicSub4.Add "vSIZE", Array(height, width)
dicSub3.Add "USE_SHEAR_DEFORM", True
dicSub3.Add "SHAPE", "SB"
dicSub3.Add "DATATYPE", 2
dicSub3.Add "SECT_I", dicSub4
dicSub2.Add "SECTTYPE", "DBUSER"
dicSub2.Add "SECT_NAME", "Rectangular"
dicSub2.Add "SECT_BEFORE", dicSub3
dicSub1.Add modelID(2, 1), dicSub2
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("POST", "/db/sect", body)
Debug.Print response
Set dicMain = Nothing: Set dicSub1 = Nothing
Set dicSub2 = Nothing: Set dicSub3 = Nothing: Set dicSub4 = Nothing
'Create Node Body and Request API
Set dicMain = New Dictionary: Set dicSub1 = New Dictionary
Dim num_division As Long
Dim interval As Double
num_division = 20
interval = length / num_division
For i = 0 To num_division
Set dicSub2 = New Dictionary
dicSub2.Add "X", i * interval
dicSub2.Add "Y", 0
dicSub2.Add "Z", 0
dicSub1.Add modelID(3, 1) + i, dicSub2
Set dicSub2 = Nothing
Next i
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("POST", "/db/node", body)
Debug.Print response
Set dicMain = Nothing: Set dicSub1 = Nothing
'Create Element Body and Request API
Set dicMain = New Dictionary: Set dicSub1 = New Dictionary
For i = 0 To num_division
Set dicSub2 = New Dictionary
dicSub2.Add "TYPE", "BEAM"
dicSub2.Add "MATL", modelID(1, 1)
dicSub2.Add "SECT", modelID(2, 1)
dicSub2.Add "NODE", Array(modelID(3, 1) + i, modelID(3, 1) + i + 1)
dicSub1.Add modelID(4, 1) + i, dicSub2
Set dicSub2 = Nothing
Next i
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("POST", "/db/elem", body)
Debug.Print response
Set dicMain = Nothing: Set dicSub1 = Nothing
'Create Boundary Body and Request API
Set dicMain = New Dictionary: Set dicSub1 = New Dictionary
Set dicSub2 = New Dictionary: Set dicSub3 = New Dictionary
dicSub3.Add "ID", 1
dicSub3.Add "CONSTRAINT", "1111000"
dicSub2.Add "ITEMS", Array(dicSub3)
dicSub1.Add modelID(3, 1), dicSub2
Set dicSub2 = Nothing: Set dicSub3 = Nothing
Set dicSub2 = New Dictionary: Set dicSub3 = New Dictionary
dicSub3.Add "ID", 1
dicSub3.Add "CONSTRAINT", "0111000"
dicSub2.Add "ITEMS", Array(dicSub3)
dicSub1.Add modelID(3, 1) + num_division, dicSub2
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("POST", "/db/cons", body)
Debug.Print response
Set dicMain = Nothing: Set dicSub1 = Nothing
Set dicSub2 = Nothing: Set dicSub3 = Nothing
'Create Load Cases and Request API
Set dicMain = New Dictionary: Set dicSub1 = New Dictionary
For i = 0 To loadCase.Rows.Count - 1
Set dicSub2 = New Dictionary
dicSub2.Add "NAME", loadCase(i + 1, 2)
dicSub2.Add "TYPE", "USER"
dicSub1.Add i + 1, dicSub2
Set dicSub2 = Nothing
Next i
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("POST", "/db/stld", body)
Debug.Print response
Set dicMain = Nothing: Set dicSub1 = Nothing
'Create Self-Weight Load Body and Request API
Set dicMain = New Dictionary: Set dicSub1 = New Dictionary
Set dicSub2 = New Dictionary
dicSub2.Add "LCNAME", loadCase(1, 2)
dicSub2.Add "FV", Array(0, 0, -1)
dicSub1.Add "1", dicSub2
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("POST", "/db/bodf", body)
Debug.Print response
Set dicMain = Nothing: Set dicSub1 = Nothing
Set dicSub2 = Nothing
'Create Beam Load Body and Request API
Set dicMain = New Dictionary: Set dicSub1 = New Dictionary
For i = 0 To num_division - 1
Set dicSub2 = New Dictionary: Set dicSub3 = New Dictionary
dicSub3.Add "ID", 1
dicSub3.Add "LCNAME", loadCase(2, 2)
dicSub3.Add "CMD", "BEAM"
dicSub3.Add "TYPE", "UNILOAD"
dicSub3.Add "DIRECTION", direction
dicSub3.Add "D", Array(0, 1)
dicSub3.Add "P", Array(loadValue, loadValue)
dicSub2.Add "ITEMS", Array(dicSub3)
dicSub1.Add modelID(4, 1) + i, dicSub2
Set dicSub2 = Nothing: Set dicSub3 = Nothing
Next i
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("POST", "/db/bmld", body)
Debug.Print response
Set dicMain = Nothing: Set dicSub1 = Nothing
'Create Load Combinations Body and Request API
Set dicMain = New Dictionary: Set dicSub1 = New Dictionary
Set dicSub2 = New Dictionary
Dim vCOMB() As Object
ReDim vCOMB(loadCase.Rows.Count - 1)
For i = 0 To loadCase.Rows.Count - 1
Set dicSub3 = New Dictionary
dicSub3.Add "ANAL", "ST"
dicSub3.Add "LCNAME", loadCase(i + 1, 2)
dicSub3.Add "FACTOR", loadCase(i + 1, 1)
Set vCOMB(i) = dicSub3
Set dicSub3 = Nothing
Next i
dicSub2.Add "NAME", "Comb1"
dicSub2.Add "ACTIVE", "ACTIVE"
dicSub2.Add "iTYPE", 0
dicSub2.Add "vCOMB", vCOMB
dicSub1.Add "1", dicSub2
dicMain.Add "Assign", dicSub1
body = JsonConverter.ConvertToJson(dicMain)
response = WebRequest("POST", "/db/lcom-gen", body)
Debug.Print response
Set dicMain = Nothing: Set dicSub1 = Nothing
Set dicSub2 = Nothing
End Sub
- 앞서 작성한 Sub 모듈을 실행할 수 있도록 버튼을 생성합니다. Developer 탭에서 버튼을 선택합니다. (Developer 도구는 Excel Options의 Customize Ribbon 설정에서 활성화할 수 있습니다.)
- 적절한 위치에 버튼을 생성한 후, 아래와 같이 실행 가능한 매크로 모듈 목록을 확인할 수 있습니다. 미리 삽입해 둔 Sub 모듈을 선택하여 적용합니다.
- MIDAS CIVIL NX를 실행하고 API 서버에 연결한 뒤, API Settings에서 base URL/MAPI-Key를 입력하고 버튼을 실행합니다.
위 과정을 완료한 첨부 파일을 참고하시기 바랍니다.
이제 의도한 구조가 MIDAS CIVIL NX에 생성되었습니다.
추가 예제
Excel VBA를 이용한 PSC Beam Girder
본 PSC Beam Girder는 한국 도로교 설계기준(Highway Bridge Design Standard)을 기반으로 한 Steel Crossbeam 예제이며, Excel VBA를 사용합니다.
구조 엔지니어를 위한 최고의 도구
VBA는 Excel로 작성된 구조 계산 시트와 결합될 때 가장 큰 강점을 발휘할 수 있습니다.
특히 해석 결과를 계산 시트에 반복적으로 입력해야 하는 경우, API는 매우 좋은 선택이 될 수 있습니다.
VBA와 함께 MIDAS Open API의 첫걸음을 시작해 보시기 바랍니다.