본문으로 바로가기

TCP Socket Router 예제를 통한 Electron Application 작성방법에 대한 연재가 완료되었습니다.

 

Electron + Vue.js 애플리케이션 만들기

1. Electron 프로젝트 생성하기(Create Electron Application Project)

2. Electron IPC 통신(Electron Architecture, IPC Main/IPC Renderer)

3. TCP Router 기능 구현(Implements TCP Router Communication)

4. 화면 UI 구성(Main Window UI)

5. 환경설정 구현하기(Preferences Window)

6. 메뉴 사용하기(Application Menu & Context Menu)

7. 시스템 트레이 사용 및 창 최소화(System Tray & Minimize to Tray)

8. Bootstrap Vue와 Font Awesome 사용하기(Using Bootstrap Vue & Font Awesome)

9. Dark Layout과 Frameless Window(Dark Layout & Frameless Window)

10. 빌드 및 배포, 자동 업데이트(Build, Auto Updater)

 

 

이번 포스트에서는 시스템 트레이를 사용하는 방법과 창 최소화시에 트레이로 이동하는 방법, 최소화된 창으로 시작하기, 운영체제 로그인시에 자동으로 시작하게 환경설정 옵션을 적용하는 방법에 대해서 설명합니다.

 

시스템 트레이 및 최소화 시작

환경설정 추가하기

환경설정에 5개의 옵션을 추가로 설정합니다.

  • 운영체제 시작 시 프로그램 자동시작 : 운영체제 로그인 시 TCP Socket Router 애플리케이션을 자동으로 실행합니다.
  • 프로그램 시작 시 서비스 자동시작 : 프로그램 시작시에 TCP Socket Router 기능을 자동으로 시작합니다.
  • 프로그램 시작 시 최소화로 시작 : 프로그램 시작 시 최소화하여 실행합니다.
  • 창을 최소화할 때 시스템 트레이로 숨기기 : 창 최소화하면 시스템 트레이로 애플리케이션을 이동합니다.
  • 창을 닫을 때 시스템 트레이로 숨기기 : 창을 닫을 경우 시스템 트레이로 애플리케이션을 이동합니다.

프로그램 일반설정 추가하기

시스템 트레이 사용하기

/src/main/window/tray-manager.js 을 신규로 생성하고 아래와 같이 구현합니다. Menu.buildFromTemplate를 사용하여 메뉴를 신규로 생성하고 트레이에 메뉴를 추가합니다. 그리고 시스템 트레이의 아이콘을 더블클릭했을 경우의 실행하는 기능도 정의합니다.

import { app, Tray, Menu } from "electron";
import CommonUtils from "../shared/common-utils";

let tray;
export default (() => {
    class TrayManager {
        constructor(win) {
            this.win = win;

            const trayicon = CommonUtils.icon(16);

            tray = new Tray(trayicon);
            const menu = Menu.buildFromTemplate([
                {
                    label: "Show Application",
                    click : () => {
                        this.win.show();
                    }
                },
                {
                    label : "Preferences",
                    click : () => {
                        // console.log("Preference....");
                        if(app.preference) app.preference.show();
                    }
                },
                {
                    type : "separator"
                },
                {
                    label : "Quit",
                    click : () => {
                        app.isQuiting = true;
                        app.quit();
                    }
                }
            ]);
            tray.setToolTip("TCP Socket Router");
            tray.setContextMenu(menu);

            tray.on("double-click", () => {
                this.win.show();
            });
        }
    }


    return {
        init(win) {
            if(!TrayManager.instance) {
                if(!win) {
                    throw new Error("윈도우 객체의 인스턴스가 필요합니다.");
                }
                TrayManager.instance = new TrayManager(win);
            }
            return TrayManager.instance;
        }
    };
})();

/src/main/index.js의 init() 함수에서 시스템 트레이 초기화코드를 추가합니다.

import { app, ipcMain } from 'electron'
import MainWindow from './window/main-window'
import createMainMenu from './window/main-menu'
import SystemTray from './window/tray-manager'
import PreferencesManager from "./window/preferences-manager";

let mainWindow = null;
function init() {
    mainWindow = MainWindow.create();
    mainWindow.on('closed', () => {
        mainWindow = null
    });

    // 메인 메뉴 생성하기
    createMainMenu(mainWindow);

    // 환경설정 관리자
    app.preference = PreferencesManager.getInstance(mainWindow);

    // 시스템 트레이 생성하기
    SystemTray.init(mainWindow);
    
    ......(이하생략)......

 

환경설정 옵션 반영하기

운영체제 시작 시 프로그램 자동시작

프로그램 자동시작을 위하여 auto-launch 모듈을 추가설치하였습니다. /src/main/window/preferences-manager.js 파일을 아래와 같이 코드를 추가합니다. 환경설정 저장 시에 자동시작을 등록하는 코드를 삽입합니다.

......(상단생략)......
            ipcMain.on("save-preferences", (event, data) => {
                Object.keys(data).forEach((key) => {
                    this.preferences[key] = data[key];
                });
                // console.log("SAVE_PREFERENCES", prefs);
                this.preferences.save();

                // 운영체제 로그인시 자동시작 옵션 적용하기
                this.setAutoLaunch(this.preferences.common.autostartup);

......(중간생략)......

        // https://www.npmjs.com/package/auto-launch
        setAutoLaunch(autoStartup) {
            var AutoLaunch = require('auto-launch');

            var autoLauncher = new AutoLaunch({
                name: 'TCP Socket Router',
                // path: '/Applications/TCPSocketRouter.app',       // path: app.getPath('exe'),
            });

            autoLauncher.isEnabled()
            .then(function(isEnabled){
                if(autoStartup) {
                    if(isEnabled){ return; }
                    autoLauncher.enable();
                } else {
                    if(!isEnabled){ return; }
                    autoLauncher.disable();
                }
            })
            .catch(function(err){
                // handle error
            });
        }
        
......(이하생략)......        

 

프로그램 시작 시 서비스 자동시작

/src/main/index.js의 init() 함수에 TCPRouterLauncher 실행코드를 아래와 같이 수정합니다.

import { app } from 'electron'
import MainWindow from './window/main-window'
import createMainMenu from './window/main-menu'
import SystemTray from './window/tray-manager'
import PreferencesManager from "./window/preferences-manager";
import TCPRouterLauncher from './shared/tcp-router-launcher';

let mainWindow = null;
function init() {
    ......(중간생략)......

    // TCP Socket Router 인스턴스 생성
    const launcher = TCPRouterLauncher.getInstance();
    
    // 프로그램 시작시 서비스 자동시작 환경 적용하기
    const prefs = PreferencesManager.getInstance().get();
    if(prefs.common.autoservice) {
        launcher.execute();
    }
}

......(이하생략)......

프로그램 시작 시 최소화로 시작

/src/main/window/main-window.js 파일 내용 중 창이 시작할 때 창을 숨겨 시작한 다음 보여질 준비가 되면 환경설정내용에 따라 창을 보일지 숨길지를 결정합니다.

......(상단생략)......

class MainWindow {
    constructor () {
        const appicon = CommonUtils.icon(64);
        let window = new BrowserWindow({
            width: 800,
            height: 540,
            useContentSize: true,
            icon: appicon,
            resizable: false,       // 창크기 조절 안함
            minimizable: true,      // 창최소화 활성화
            maximizable: false,     // 창최대화 비활성화
            webPreferences : {
                devTools : false,   // 개발자도구 비활성화
            },
            show: false             // 숨겨서 시작하기
        })
        
        window.loadURL(winURL);

        // 시작시 최소화로 시작 환경설정 적용하기.. show: false 로 시작
        window.once('ready-to-show', () => {
            const prefs = PreferencesManager.getInstance().get();
            if(!prefs.common || !prefs.common.minimizestart || prefs.common.minimizestart == false) {
                window.show();
            }
        });

......(이하생략)......

창을 최소화할 때 시스템 트레이로 숨기기

/src/main/window/main-window.js 파일 내용 중 메인 윈도우의 최소화 이벤트 발생시에 옵션에 따라 추가로직을 수행하도록 합니다.

......(상단생략)......
        window.on('minimize', (event) => {
            const prefs = PreferencesManager.getInstance().get();
            if(prefs.common && prefs.common.minimizeToTray === true) {
                event.preventDefault();
                if(process.platform === "darwin") {
                    window.minimize();
                } else {
                    window.hide();
                }
            }
        });
......(이하생략)......        

창을 닫을 때 시스템 트레이로 숨기기

/src/main/window/main-window.js 파일 내용 중 메인 윈도우의 닫기 이벤트 발생시에 옵션에 따라 추가로직을 수행하도록 합니다. app.isQuiting 옵션을 추가구현하여 실제 프로그램을 종료하는 지, 창을 닫는 것인지 구분하여 사용합니다. 프로그램을 실제 종료할 경우에 app.isQuiting 옵션을 true로 먼저 설정해야합니다.

......(상단생략)......
         window.on('close', (event) => {
            const prefs = PreferencesManager.getInstance().get();
            if(!app.isQuiting && prefs.common && prefs.common.closeToTray === true) {
                event.preventDefault();
                if(process.platform === "darwin") {
                    window.minimize();
                } else {
                    window.hide();
                }
            }
            return false;
        });
......(이하생략)......

프로그램의 종료는 다음과 같이 처리합니다.

메뉴에서의 종료처리

/src/main/window/main-menu.js의 종료코드를 다음과 같이 수정합니다.

                    label : "Exit",
                    click : () => {
                        app.isQuiting = true;
                        app.quit();
                    }

시스템 트레이의 종료처리

/src/main/window/tray-manager.js 의 종료코드를 다음과 같이 수정합니다.

                {
                    label : "Quit",
                    click : () => {
                        app.isQuiting = true;
                        app.quit();
                    }
                }

맥킨토시의 모든 창닫기 시 애플리케이션 종료처리

/src/main/index.js 에서 애플리케이션 이벤트처리로직을 아래와 같이 수정합니다.

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.isQuiting = true;
        app.quit()
    }
})

 

참고자료

 

소스코드

본 포스트 관련 소스코드는 여기에서 다운로드 가능합니다.

 

 

728x90