엑셀 VBA에서 넘어오면 제일 먼저 찾게 되는 게 InputBox입니다. 매크로 실행 중에 날짜나 이름 같은 값을 하나 물어보고 그 값으로 작업을 이어 가는 식이죠. 구글 스프레드시트의 Apps Script에서는 SpreadsheetApp.getUi()로 얻은 UI 객체의 prompt()가 같은 역할을 합니다.

    // InputBox
    var ui = SpreadsheetApp.getUi();
      var ask = ui.prompt("What is your name?", ui.ButtonSet.YES_NO);
      var response = ask.getResponseText();
     if(ask.getSelectedButton() == ui.Button.YES) {
        ui.alert(response);
      }

이 코드를 함수 안에 넣고 실행하면 시트 화면에 "What is your name?"이라는 입력 대화상자가 뜨고, 아래에 "예/아니요" 버튼이 붙습니다. 이름을 입력하고 "예"를 누르면 입력한 글자가 그대로 알림창(ui.alert)으로 다시 표시됩니다.

광고

prompt()가 돌려주는 것

VBA InputBox는 입력한 문자열을 바로 돌려주지만, prompt()는 응답 객체를 돌려줍니다. 여기서 두 가지를 꺼내 씁니다.

  • getResponseText() : 입력 칸에 적힌 문자열
  • getSelectedButton() : 사용자가 누른 버튼 (ui.Button.YES, ui.Button.NO 등)

입력 칸이 비어 있어도 "예"를 누를 수 있고, 반대로 글자를 다 적어 놓고 "아니요"를 누를 수도 있습니다. 그래서 위 코드처럼 버튼을 먼저 확인한 다음에 입력값을 쓰는 순서가 맞습니다. 대화상자 오른쪽 위 X로 닫으면 ui.Button.CLOSE가 들어오니, "예가 아니면 모두 취소"로 처리해 두면 이 경우까지 한 번에 걸러집니다.

버튼 구성은 두 번째 인자로 정합니다. 예제의 YES_NO 말고도 ui.ButtonSet.OK, OK_CANCEL, YES_NO_CANCEL을 쓸 수 있습니다. 값을 입력받는 용도라면 "확인/취소"가 더 자연스러워서 저는 OK_CANCEL을 주로 쓰고, 이때는 비교도 ui.Button.OK로 바꿔야 합니다. 대화상자 제목을 따로 주고 싶으면 ui.prompt("제목", "안내 문구", ui.ButtonSet.OK_CANCEL)처럼 인자를 세 개로 넘기면 됩니다.

실행할 때 막히는 지점

SpreadsheetApp.getUi()는 스프레드시트에 연결된(시트에서 "확장 프로그램 > Apps Script"로 연) 스크립트에서만 동작합니다. 그리고 대화상자는 시트를 열어 놓은 사람 화면에 뜨는 것이라, 편집기에서 실행하면 편집기 탭이 아니라 스프레드시트 탭에 떠 있습니다. 실행이 멈춘 것 같으면 시트 탭을 확인해 보세요. 시간 기반 트리거처럼 화면 없이 도는 실행에서는 UI를 띄울 수 없어 오류가 납니다.

입력값은 항상 문자열로 들어오므로 숫자로 계산하려면 Number(response)로 바꾸고 isNaN()으로 한 번 검사하는 게 안전합니다. 메뉴에 "데이터 가져오기" 같은 항목을 만들어 두고, 눌렀을 때 시작 날짜를 prompt()로 물어본 뒤 그 날짜 이후 행만 처리하는 식으로 응용하면 VBA 매크로와 거의 같은 사용감이 나옵니다.

잘못 입력하면 다시 묻기

숫자를 받아야 하는데 사용자가 글자를 넣거나 비워 둔 채 확인을 누르면, 그냥 끝내기보다 다시 물어보는 게 친절합니다. 아래 함수는 시작 행 번호를 받아서 돌려주고, 취소하면 null을 돌려줍니다.

function askStartRow() {
  var ui = SpreadsheetApp.getUi();
  while (true) {
    var res = ui.prompt('시작 행', '처리를 시작할 행 번호를 입력하세요.', ui.ButtonSet.OK_CANCEL);
    if (res.getSelectedButton() != ui.Button.OK) return null;   // 취소 또는 X
    var n = Number(res.getResponseText().trim());
    if (Number.isInteger(n) && n >= 2) return n;
    ui.alert('2 이상의 정수를 입력하세요.');
  }
}

Number('')는 0이 되기 때문에 빈 칸으로 확인을 누른 경우도 n >= 2 조건에서 걸러집니다. 머리글이 1행에 있다고 보고 2 이상만 받게 했는데, 시트 구조에 맞게 바꾸면 됩니다. 부르는 쪽에서는 var row = askStartRow(); if (row === null) return;처럼 취소를 먼저 처리하고 다음 작업으로 넘어가면 됩니다.

prompt()로 안 되는 것

입력 칸은 한 줄짜리 하나뿐입니다. 시작일과 종료일처럼 값 두 개가 필요하면 prompt()를 두 번 띄우거나, 칸이 여러 개인 입력 창이 필요할 때는 HtmlService로 HTML 대화상자를 만들어야 합니다. 기본값을 미리 채워 두는 기능도 없어서, 매번 같은 값을 넣게 되는 작업이라면 직전 입력값을 시트의 특정 셀에 저장해 두고 안내 문구에 "지난번 값: ..." 식으로 보여 주는 정도로 보완합니다.

예전 예제에서는 Browser.inputBox()도 보이는데, 이쪽은 입력값을 문자열로 바로 돌려주고 취소하면 'cancel'이라는 글자를 돌려주는 방식이라 사용자가 실제로 cancel을 입력한 경우와 구분이 안 됩니다. 새로 짜는 코드라면 버튼을 따로 확인할 수 있는 ui.prompt() 쪽이 낫습니다. 같은 getUi()는 구글 문서(DocumentApp)와 슬라이드(SlidesApp)에도 있어서, 거기 붙인 스크립트에서도 같은 방식으로 값을 물어볼 수 있습니다.