7
2

More than 1 year has passed since last update.

NimでElectron(デスクトップアプリ)

Last updated at Posted at 2021-12-11

連続で忙しい日にアドベントカレンダー入れるんじゃなかった泣
と思いながらGodotでNimを使ってゲームを作ろうかと思ったのですが
すでに似た記事があったためNim + Electronに変更します 笑

概要

実行環境

・M1 MacbookAir(2020)
・OS macOS BigSur 11.5.2
・メモリ 16GB

ディレクトリ構成

├── index.html
├── main.js ・・・コンパイル結果
├── main.nim
└── package.json
package.json
{                                                                                                                                                                                 
  "name": "electron-quick-start",
  "version": "1.0.0",
  "description": "A minimal Electron application",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },  
  "repository": "https://github.com/electron/electron-quick-start",
  "keywords": [
    "Electron",
    "quick",
    "start",
    "tutorial",
    "demo"
  ],  
  "author": "GitHub",
  "license": "CC0-1.0",
  "devDependencies": {
    "electron": "^12.0.1"
  }
}

 実行の手順

main.nimに処理を記述して以下でjsにコンパイルしてnpm startで実行できます。

$ npm install
$ nim js -d:node -o:main.js main.nim

# アプリ起動
$ npm start

NimでのElectron記述

jsライブラリのimport

まずelectronがjs製なため、jsの関数やイベントをロードする必要があります。
ここら辺は脳死で書いてしまっていいかと思います。
(動くまでに結構時間がかかりました...)

main.nim
import jsffi

{.emit: """ 
const electron = require('electron')
const path = require('path')
const url = require('url')
const net = require('net');
""".}

var
  electron {. importc, nodecl .}: JsObject
  path {. importc, nodecl .}: JsObject
  url {. importc, nodecl .}: JsObject
  console {. importc, nodecl .}: JsObject
  process {.importc, nodecl.}: JsObject
  net {.importc, nodecl.}: JsObject
  dirname {.importc: "__dirname", nodecl.}: JsObject

ウィンドウの起動設定

main.nim
let app = electron.app
var mainWindow: JsObject

proc createWindow() =
  # ウィンドウサイズを指定してjsnewを使ってウィンドウを作成
  mainWindow = jsnew electron.BrowserWindow(JsObject{width: 800, height: 600})
  mainWindow.loadURL(url.format(JsObject{
    pathname: dirname.to(cstring) & "/index.html",
    protocol: "file".cstring,
    slashes: true
  })) 

  mainWindow.on("closed", proc () =
    mainWindow = nil 
  )

イベントハンドラ

ready(起動時)
main.nim
app.on("ready", createWindow)
window-all-closed(Windowが全部閉じられた時)
main.nim
app.on("window-all-closed", proc () =
  if process.platform.to(cstring) != "darwin":
        # 終了処理
    app.quit()
)

ここでdarwinとしているのはos判定なので、
NimのOSプラットフォームを見て必要であれば追加してください。

バックグラウンドからアクティブにされた時
main.nim
app.on("activate", proc() =
  if mainWindow == nil:
    createWindow()
)

activateにcreateWindowを書く必要があるのは
macOSなどでバックグラウンド起動時にアイコンから起動で
ウィンドウを再生成する場合があるためらしいです。

以下、main.nimの全文です。

main.nim
import jsffi

{.emit: """
const electron = require('electron')
const path = require('path')
const url = require('url')
const net = require('net');
""".}

var
  electron {. importc, nodecl .}: JsObject
  path {. importc, nodecl .}: JsObject
  url {. importc, nodecl .}: JsObject
  console {. importc, nodecl .}: JsObject
  process {.importc, nodecl.}: JsObject
  net {.importc, nodecl.}: JsObject
  dirname {.importc: "__dirname", nodecl.}: JsObject

let app = electron.app
var mainWindow: JsObject

proc createWindow() =
  mainWindow = jsnew electron.BrowserWindow(JsObject{width: 800, height: 600})
  mainWindow.loadURL(url.format(JsObject{
    pathname: dirname.to(cstring) & "/index.html",
    protocol: "file".cstring,
    slashes: true
  }))

  mainWindow.on("closed", proc () =
    mainWindow = nil
  )

app.on("ready", createWindow)

app.on("window-all-closed", proc () =
  if process.platform.to(cstring) != "darwin":
    app.quit()
)

app.on("activate", proc() =
  if mainWindow == nil:
    createWindow()
)
7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2