시트가 수십 장 되는 구글 스프레드시트를 쓰다 보면 아래 탭을 좌우로 넘기며 찾는 게 꽤 번거롭습니다. Apps Script의 onOpen 은 파일을 열 때마다 자동으로 실행되는 함수라서, 여기에 사용자 메뉴를 붙여 두면 메뉴 하나로 원하는 기능을 바로 부를 수 있습니다.

메뉴 추가만 하는 최소 형태

function onOpen(event) {
  var ss = event.source;
  var menuEntries = [];
  menuEntries.push({name: "Go to sheet...", functionName: "showGoToSheet"});
  ss.addMenu("Tasks", menuEntries);
}

onOpen 이라는 이름 자체가 약속이라 따로 트리거를 등록하지 않아도 됩니다. event.source 가 지금 열린 스프레드시트이고, addMenu 에 메뉴 이름과 항목 배열을 넘기면 상단 메뉴줄에 "Tasks" 가 생깁니다. 항목의 functionName 에는 클릭했을 때 실행할 함수 이름을 문자열로 적습니다.

광고

스프레드시트 상단에 Tasks 사용자 메뉴가 추가된 화면

스크립트를 저장한 직후에는 메뉴가 안 보이는데, 파일을 새로 고침해야 onOpen 이 다시 실행되면서 나타납니다. 처음 만들었을 때 메뉴가 안 생긴다고 헤매는 경우가 대부분 이 때문입니다.

시트 목록 창에서 골라 이동하기

아래는 메뉴를 누르면 시트 이름 목록을 창으로 띄우고, 이름을 클릭하면 그 시트로 이동하는 전체 예제입니다. 맨 아래에는 그림이나 버튼에 연결해 특정 시트("Sheet5")로 바로 가는 함수도 들어 있습니다.

// Google 스프레드 시트의 특정 시트에 연결

function onOpen(event) {
  var ss = event.source;
  var menuEntries = [];
  menuEntries.push({name: "Go to sheet...", functionName: "showGoToSheet"});
  ss.addMenu("Tasks", menuEntries);
}

function showGoToSheet() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var allsheets = ss.getSheets();
  var app = UiApp.createApplication();
  app.setTitle("Go to sheet...").setWidth(800).setHeight(600);
  var table = app.createFlexTable();
  table.setCellPadding(5).setCellSpacing(0);
  var goToSheetClick = app.createServerHandler('handleGoToSheetClick');
  var widgets = [];
  for (var i = 0; i < allsheets.length; i++) {
    var sheet_name = allsheets[i].getName();
    widgets[i] = app.createHTML(sheet_name).setId(sheet_name).addClickHandler(goToSheetClick);
    table.setWidget(i, 1, widgets[i])
  }
  var panel = app.createSimplePanel();
  panel.add(table);
  app.add(panel);
  ss.show(app);
}

function handleGoToSheetClick(e) {
  var sheet_name = e.parameter.source;
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName(sheet_name);
  sheet.activate();
  var app = UiApp.getActiveApplication();
  app.close();
  return app;
}

// 버튼을 클릭하고 "Sheet5"로 이동
function showSheetByName(Name) {
   var ss = SpreadsheetApp.getActiveSpreadsheet();
   var sheet = ss.getSheetByName(Name);
   SpreadsheetApp.setActiveSheet(sheet);
}

function showSheet5() {
   showSheetByName("Sheet5");
}

showGoToSheet 는 모든 시트를 돌면서 이름을 표에 한 줄씩 넣고, 각 이름에 같은 클릭 핸들러를 붙입니다. 위젯 ID를 시트 이름으로 지정해 두었기 때문에, 핸들러에서는 e.parameter.source 로 어느 이름을 눌렀는지 알아내고 그 시트를 활성화한 뒤 창을 닫습니다.

UiApp 부분은 지금 쓸 수 없다

창을 만드는 데 쓴 UiApp 은 구글이 지원을 끝낸 서비스라서, 지금 이 코드를 그대로 넣으면 showGoToSheet 를 실행할 때 오류가 납니다. 같은 기능을 만들려면 HtmlService 로 HTML 대화상자를 띄우고, 클릭 시 google.script.run 으로 서버 함수를 호출해 시트를 활성화하는 구조로 바꿔야 합니다. 메뉴를 붙이는 쪽도 요즘은 SpreadsheetApp.getUi().createMenu("Tasks").addItem(...).addToUi() 형태를 많이 씁니다.

HtmlService로 바꾼 시트 이동 창

위 설명대로 옮기면 파일이 두 개가 됩니다. 스크립트 편집기에서 기존 onOpen, showGoToSheet, handleGoToSheetClick 을 지우고 아래 코드를 넣은 뒤, "파일 추가 → HTML" 로 GoToSheet 라는 이름의 HTML 파일을 하나 만듭니다.

function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('Tasks')
    .addItem('Go to sheet...', 'showGoToSheet')
    .addToUi();
}

function showGoToSheet() {
  var names = SpreadsheetApp.getActiveSpreadsheet().getSheets().map(function (s) {
    return s.getName();
  });
  var t = HtmlService.createTemplateFromFile('GoToSheet');
  t.names = names;
  SpreadsheetApp.getUi().showModalDialog(
    t.evaluate().setWidth(300).setHeight(400), 'Go to sheet...');
}

function goToSheet(name) {
  SpreadsheetApp.getActiveSpreadsheet().getSheetByName(name).activate();
}
<!DOCTYPE html>
<html>
  <body>
    <? for (var i = 0; i < names.length; i++) { ?>
      <div><a href="#" onclick="go(this.textContent); return false;"><?= names[i] ?></a></div>
    <? } ?>
    <script>
      function go(name) {
        google.script.run.withSuccessHandler(function () {
          google.script.host.close();
        }).goToSheet(name);
      }
    </script>
  </body>
</html>

HTML 쪽의 <? ?> 는 템플릿 문법이라, 서버에서 넘긴 names 배열을 돌면서 시트 이름을 링크로 하나씩 찍어 줍니다. 이름을 누르면 google.script.run 이 서버의 goToSheet 를 부르고, 시트가 활성화되면 google.script.host.close() 로 창을 닫습니다. 예전 코드에서 위젯 ID로 시트 이름을 넘기던 부분이 여기서는 링크 글자 자체를 넘기는 방식으로 바뀐 셈입니다.

처음 메뉴를 누르면 권한 승인 창이 뜹니다. 스크립트가 시트를 읽고 대화상자를 띄우려면 한 번은 승인이 필요하니 계정을 골라 허용하면 되고, 그 뒤로는 바로 열립니다. 그리고 onOpen 같은 단순 트리거는 그 파일을 편집할 수 있는 사람이 열 때 실행됩니다. 보기 권한만 있는 사람에게는 메뉴가 안 보일 수 있으니, 여럿이 같이 쓰는 파일이라면 이 점을 미리 알려 두세요.

반면 맨 아래 showSheetByName / showSheet5 는 지금도 그대로 동작합니다. 시트에 도형이나 그림을 넣고 "스크립트 할당"에서 showSheet5 를 지정하면, 그 그림을 누를 때마다 Sheet5로 이동합니다. 목차 시트를 하나 만들어 시트별 버튼을 늘어놓으면 간단한 내비게이션이 됩니다. 시트 이름을 바꾸면 함수 안의 문자열도 같이 고쳐야 한다는 점만 기억해 두세요.