Electron

Electron, 애플리케이션 메뉴(Application Menu)

iKay 2018. 10. 28. 16:39
반응형

0. 들어가며

우리가 사용하는 거의 모든 애플리케이션에는 메뉴가 있다. 그리고 메뉴는 애플리케이션에서 중요한 역할을 한다. 예를 들어 메모장 애플리케이션에서는 메뉴를 통해 작업 중인 문서를 저장하거나 불러올 수 있고 애플리케이션을 을 종료할 수도 있다. 메뉴에는 애플리케이션 창 위쪽에 있는 애플리케이션 메뉴(application menu)와 오른쪽 클릭을 하면 나타나는 콘텍스트 메뉴(context menu)가 있다. 이번 포스팅에서는 Electron에서 이 두 메뉴를 구현하는 방법을 알아본다. 

 

1. 애플리케이션 메뉴(Application Menu)

에플리케이션 메뉴는 애플리케이션 창 상단에 보이는 메뉴이다. 흔히 파일을 저장하고 읽을 때, 어떤 도움이 필요할 때 사용한다. 

 

프로젝트 디렉토리를 생성하고 npm init을 해 package.json을 생성한다. 그 후 다음과 같이 'main.js'를 작성하자. 지난 번에 작성했던 main.js와 다른 점은 Menu가 추가됐다는 것이다.  

 

const {app, BrowserWindow, Menu} = require('electron');
const menuTemplate = require('./menuTemplate');

let win;

function createWindow() {
  win = new BrowserWindow({width: 800, height: 600});
  /* load local .html file*/
  win.loadURL(`file://${__dirname}/index.html`);
}

const menu = Menu.buildFromTemplate(menuTemplate);

Menu.setApplicationMenu(menu);
app.on('ready', createWindow);

 

프로젝트 디렉토리에 'menuTemplate.js'라는 js 파일을 만들고 다음과 같이 입력해 menu template를 만든다. 이 template은 Menu 모듈의 buildFromTemplate 메소드에 넘겨진다. submenu중 role(undo, redo 등... )은 이미 정의된 기능으로서, 유저가 직접 구현할 필요 없이 그대로 사용할 수 있다. 그래서 click( ) 이라는 함수를 가질 수 없다. 하지만, 'Learn More'과 같이 사용자가 정의 메뉴에는 click( )에 직접 함수를 정의할 수 있다.  

 

roles에 대한 더 자세히 알려면 여기를 참고하자. 

 

/* menuTemplate.js */

const template = [
  {
    label: 'Edit',
    submenu: [
      {role: 'undo'},
      {role: 'redo'},
      {type: 'separator'},
      {role: 'cut'},
      {role: 'copy'},
      {role: 'paste'},
      {role: 'pasteandmatchstyle'},
      {role: 'delete'},
      {role: 'selectall'}
    ]
  },
  {
    label: 'View',
    submenu: [
      {role: 'reload'},
      {role: 'forcereload'},
      {role: 'toggledevtools'},
      {type: 'separator'},
      {role: 'resetzoom'},
      {role: 'zoomin'},
      {role: 'zoomout'},
      {type: 'separator'},
      {role: 'togglefullscreen'}
    ]
  },
  {
    role: 'window',
    submenu: [
      {role: 'minimize'},
      {role: 'close'}
    ]
  }, 
  {
    role: 'help',
    submenu: [
      {
        label: 'Learn More',
        click () { require('electron').shell.openExternal('https://electronjs.org') }
      }
    ]
  }
];

module.exports = template;

 

index.html은 다음과 같이 빈 파일을 우선 만들자. 내용이 없으므로 Electron으로 main 프로세스를 실행 시킨 후 renderer 프로세스는 상단 메뉴만 가진 빈 화면을 render할 것이다. 

 

 

<!-- index.html -->

<body>
<script type = "text/javascript">
</script>
</body>

 

cmd에서 Electron으로 main.js를 실행시키면 다음과 같은 창이 뜰 것이고 menuTemplate.js에서 지정한 메뉴들을 확인할 수 있다. 

 

 

2. 콘텍스트 메뉴(Context Menu)

콘텍스트 메뉴는 마우스로 오른쪽 클릭을 할 때 나타나는 메뉴이다. 부가적인 기능, 다른 기능을 사용하고 싶을 때 사용한다. 

 

조금 전에 index.html을 생성할 때 내용이 빈 html 파일을 생성했다. 이제는 콘텍스트 메뉴를 추가하기 위해 아래와 같이 소스코드를 입력하자. 참고로, Menu는 메인 프로세스에서 사용 가능한 것이기 때문에, renderer 프로세스에서 사용하기 위해서는 아래와 같이 remote 모듈을 선언해줘야 한다. 

 

정적(static) 또는 동적(dynamic)으로 설정할 수 있다. main 프로세스에 있는 Menu는 정적(static)으로 선언됐으나, 아래 renderer 프로세스에 있는 menu는 인스턴스에 의해 동적으로 항목들이 추가 됨을 볼 수 있다.   

 

참고로, 웹 브라우저에서 기본적으로 동작하는 오른쪽 클릭을 막으려면 아래와 같이, window.addEventLister('contextmenu', (e) => {  e.preventDefault(); }, false); 해주면 된다.   

 

<!-- index.html -->

<body>
<script type = "text/javascript">
  const {remote} = require('electron')
  const {Menu, MenuItem} = remote

  const menu = new Menu();

  menu.append(new MenuItem ({
    label: 'MenuItem1',
    click() { console.log('item 1 clicked') }
  }));
  menu.append(new MenuItem({type: 'separator'}));
  menu.append(new MenuItem({label: 'MenuItem2', type: 'checkbox', checked: true}));

  window.addEventListener('contextmenu', (e) => {
    e.preventDefault();
    menu.popup();
  }, false);
</script>
</body>

 

 

electron으로 main.js를 실행 시키면 빈 화면이 나온다. 빈 화면에서 오른쪽 클릭을 하면, 다음과 같이 위에서 지정했던 메뉴들이 나타난다. 그리고 콘솔에서 MenuItem1이 클릭될 때 마다 'item 1 clicked'라는 문자열이 출력된다. MenuItem2의 체크박스도 클릭할 때 마다 선택, 해제된다. 이렇듯 각 lable에 click( ) 사용자가 원하는 함수를 정의하면 원하는 콘텍스트 메뉴를 구현할 수 있을 것이다. 

 

 

 

3. 결론

Electron 애플리케이션에서 사용되는 두 가지 메뉴, 애플리케이션 메뉴(Application Menu), 콘텍스트 메뉴(Contect Menu)에 대해 알아봤다. 애플리케이션을 만들 때 메뉴를 적절히 구성하는 것은 매우 중요하다.    

 

4. 소스코드

https://github.com/hgs0426/electron/tree/master/menu

 

5. 참고

[1] https://electronjs.org/docs/api/menu

 

[2] https://electronjs.org/docs/api/menu-item

 

[3] https://www.tutorialspoint.com/electron/electron_menus.htm

반응형