descjop で遊ぼう day 14 : アプリケーションメニューを作ろう

descjop (Electron + Clojure) Advent Calendar 2015 - Adventarの14日目です。

Story Permalink

さて、今日からはメニュー周りの解説を書いていきます。

デスクトップアプリケーションでは、ウインドウ内の操作以外にもメニューを使った操作を頻繁に使います。

ただ、アプリケーションのメニューについては、WindowsとOSXで考え方が異なります。

デスクトップアプリケーションのメニューについて考える

Windowsでは、アプリケーションのウインドウ上部にメニューがつきます。

ただOSXでは、デスクトップの上部にメニューバーが常に表示されていて、現在利用中のアプリケーションのメニューが反映されます。

また、アプリケーションのライフサイクルについても考え方が違います。

Windowsだとウインドウを閉じるとアプリケーションは終了してしまいますが、OSXではウインドウを閉じてもアプリケーションは終了しません。(まあ、終了するものもありますが)

メニューをつくる際はその辺りの違いも考えておきましょう。

まずは簡単なメニューを実装してみましょう。

今回つくるアプリケーションメニュー

今回はとりあえず、OSX用のアプリを作っていきます。

Windowsは、一旦はサポート外です(動くかもしれませんが)

機能については以下のとおりとします。

  • メニューは、アプリケーション名のメニューとHelpのみ
  • アプリケーション名のメニューでは、アプリケーションの終了ができる
  • Helpメニューは、OSXの標準のヘルプメニューの機能と、About this app的なものがある

つまりメニューは2個です。

メニュー追加の手順

Electronにおけるアプリケーションメニューは、メニューの組み立て用のmenuモジュールと、個々のメニューを構成するmenu-itemモジュールで作成します。

個々のメニューは入れ子構造に出来、下位階層のメニューはサブメニューと呼ばれます。

Electronのmenuモジュールで扱えるメニューは、アプリケーションメニューとコンテキストメニューがあります。

今回は、アプリケーションメニューのみ作成します。

プロジェクトの作成

今まで作ってきたプロジェクトは一旦置いておいて、新しいプロジェクトを作成します。

任意のディレクトリで下記コマンドを実行します。

$ lein new descjop hello_menu +om

プロジェクトの作成が終わったので、プロジェクトディレクトリに移動しておきます。

src/hello_menu/core.cljを今回は編集していきます。

まずは、OSの判定をとっておきましょう。

OSXかどうかの判定をとっておく

デスクトップアプリのメニューに対する考え方は、OSXだけ異なるのでOSXかどうかだけ判定します。

実は判定ロジック自体は、descjopのプロジェクトテンプレートに入っているのでこれを利用して下記のようにします。

(def is-mac (= (.-platform nodejs/process) "darwin"))

これでis-mactruefalseかどうかで判定できるようになりました。

各種モジュールの読み込みをする

今回新たに使うモジュールは、shellmenuです。

shellは、ブラウザを開くのに使います。

メニュー関係のモジュールは、menumenu-itemがありますが、今回はメニューのテンプレートから一気に作成するので、menuしか使いません。

ということで、下記コードをis-macの下に書きます。

(def Shell (nodejs/require "shell"))
  
(def ElectronMenu (nodejs/require "menu"))

続いて、appからアプリケーション名を取得しておきましょう。

OSXのメニューのアプリケーション名として使います。

下記コードを、ElectronMenuの定義の下に書きます。

(def app-name (.getName app))

続いて、メニューの構成を記述していきます。

メニューの構成を決める

Electronのアプリケーションメニューの雛形は、メニューごとのマップが連続したデータとして作ることが出来ます。

ただ、OSXのときとWindows/Linuxのときはメニューを分けたいので、下記のように分岐させてみました。

(def menu-template
  "メニュー構成"
  (if is-mac
    [{:label   app-name
      :submenu [{:label   "Quit."
                 :accelerator "Command+Q"
                 :click (fn [] (.quit app))}]}
     {:label   "Help"
      :role    "help"
      :submenu [{:label   "About this mac app"
                 :accelerator "Command+H"
                 :click (fn [] (.openExternal Shell "http://descjop.org/"))}]}]
    [{:label   "Help"
      :submenu [{:label   "About this windows/linux app"
                 :accelerator "Control+H"
                 :click (fn [] (.openExternal Shell "http://descjop.org/"))}]}]))

アプリケーションの大メニューは、

{:label "大メニューのラベル名"
 :submenu [サブメニュー]}

という風にキーワードと値のペアで記述していきます。

  • :labelは、大メニュー、サブメニュー共に指定をします。これが表示される名前になります。
  • :submenuは、メニューを開いたときに表示される子メニューで、サブメニューと呼ばれます。ここには大メニューのような形でマップを入れていくことが出来ます。
  • :acceleratorというのもコードで出て来ますが、これはショートカットです。"Command+Q"のように指定します。ちなみに、指定しているとメニューを展開したときにショートカットのヒントも表示されます。
  • :clickというキーもあるのがわかると思いますが、これはメニューを選んだときに実行される関数を指定します。今回は、ブラウザでhttp://descjop.org/を開くようにしています。ここで、shellモジュールを使っています。
  • :roleというのも指定しています。ロールを指定するとメニューにあらかじめ標準のアプリケーションに指定されている役割をあてることができます。ここでは:role "help"を指定していますが、これはヘルプという役割のメニューを設定しているということです。ヘルプの役割を指定すると、メニューを開いたときに他のアプリケーションにあるような検索窓も表示されます。

その他のアプリケーションのロールについては下記があります。

- about - Map to the orderFrontStandardAboutPanel action
- hide - Map to the hide action
- hideothers - Map to the hideOtherApplications action
- unhide - Map to the unhideAllApplications action
- front - Map to the arrangeInFront action
- window - The submenu is a "Window" menu
- help - The submenu is a "Help" menu
- services - The submenu is a "Services" menu

メニューをアプリケーションに反映させる

続いて、定義したメニューをアプリケーションに反映させましょう。

-main関数の(.on app "ready" (fn [] 処理))にあるreadyイベント内に下記を記述します。

       ;; menu build
       (.setApplicationMenu ElectronMenu
                            (.buildFromTemplate ElectronMenu (clj->js menu-template)))

その結果、-main関数は下記のようになります。

(defn -main []
  (.start crash-reporter)
 
  ;; error listener
  (.on nodejs/process "error"
    (fn [err] (.log js/console err)))
 
  ;; window all closed listener
   (.on app "window-all-closed"
     (fn [] (if (not= (.-platform nodejs/process) "darwin")
              (.quit app))))

  ;; ready listener
   (.on app "ready"
     (fn []
       (reset! *win* (BrowserWindow. (clj->js {:width 800 :height 600})))
 
       ;; when no optimize comment out
       (.loadUrl @*win* (str "file://" (.resolve path (js* "__dirname") "../index.html")))
       ;; when no optimize uncomment
       ;; (.loadUrl @*win* (str "file://" (.resolve path (js* "__dirname") "../../../index.html")))
 
       ;; menu build
       (.setApplicationMenu ElectronMenu
                            (.buildFromTemplate ElectronMenu (clj->js menu-template)))
 
       (.on @*win* "closed" (fn [] (reset! *win* nil))))))

実行してみよう

これでメニューが追加されるはずなので、コンパイルをして実行してみましょう。

メニューが2つ表示されていれば成功です。

Colophon

編集長
Greative GK. 原一浩 ( kara_d )
製版システム
Clojure / Compojure / Ring / Enlive / markdown-clj / Jetty / MySQL
Share this magazine!
Follow designudge

Magazine Archives

vol.122

2016-Feb-01

Cover

台湾に行ってきました。

今回のカバーは、台湾にて撮影したものです。

自治体Webデザイントレンドこぼれ話 : ここだよマップ

CSS Niteの年末イベントShiftでやっているセッションにデザイントレンドというのがあります。

descjop で遊ぼう day 16 : Windows版のメニューを表示する

2015年の振り返り的な一人レトロスペクティブ

そういえば、まだ2015年の振り返りをマガジンに掲載していませんでした

編集後記

vol.121

2016-Jan-14

Cover

今回のカバーは、、、UFO?

自治体Webデザイントレンドこぼれ話 : 予告

CSS Niteの年末イベントShiftでやっているセッションにデザイントレンドというのがあります。

descjop で遊ぼう day 11 : Omのコンポーネントで遊ぼう

descjop で遊ぼう day 12 : Omのコンポーネントで遊ぼうその2

descjop で遊ぼう day 13 : Clojure ワークショップでTAしてきた話

descjop で遊ぼう day 14 : アプリケーションメニューを作ろう

descjop で遊ぼう day 15 : descjop 0.5.3をリリースしました

編集後記

vol.120

2016-Jan-14

Cover

今回のカバーも、初詣に行ったときのショットです。

descjop で遊ぼう day 6 : Electronがうまくダウンロードできないとき

descjop で遊ぼう day 7 : Hello Worldを出力してみるには

descjop で遊ぼう day 8 : Om basedテンプレートを使ってみる

descjop で遊ぼう day 9 : Om basedテンプレートにボタンをつける

descjop で遊ぼう day 10 : Om basedテンプレートにボタンをつけるその2

編集後記

vol.119

2016-Jan-10

Cover

今回のカバーは、初詣に行ったときのショット。

「descjop で遊ぼう」について

「descjop で遊ぼう」というのは年末にやったアドベントカレンダーのシリーズなのですが、前段としてまずはその解説をば。

descjop で遊ぼう day 1 : はじめに

descjop で遊ぼう day 2 : 3つのテンプレート

descjop で遊ぼう day 3 : 環境構築をしよう

descjop で遊ぼう day 4 : Helpを見てみよう

descjop で遊ぼう day 5 : デフォルトアプリケーションのビルドと起動

編集後記

vol.118

2015-Oct-22

Cover

今回のカバーは、Stack Overflow DevDaysのイベントをお手伝いしたときの窓からのショット。

Vaqum Web Design Review

創刊以来延々と続くWebサイトレビュー

ミカヅキClojure : ゼロからはじめるClojure入門第2回

Clojureっていうじつに面白いプログラミング言語をとりあげていきます

インフォメーション

おすすめのイベント・勉強会情報を紹介

編集後記

vol.117

2015-Oct-07

Cover

今回は散歩道からのショット

Editor’s Picks

designudgeで扱っている内容に近いジャンルのリソースのうち気になったものなど

U.S. Web Design Standardsを見てみる

今話題となっているU.S. Web Design Standardsの周辺情報など見てみました

Bootstrap 4徹底攻略 (3)

Bootstrap 4のアルファ版がでているので使おう

インフォメーション

おすすめのイベント・勉強会情報を紹介

編集後記

vol.116

2015-Sep-28

Cover

今回は帰省した際に通った三島からのショットです

Vaqum Web Design Review

創刊以来延々と続くWebサイトレビュー

みそじ過ぎからの英語再学習

40を目前に今までサボっていた英語学習をはじめました

Bootstrap 4徹底攻略 (2)

Bootstrap 4のアルファ版がでているので使おう

ミカヅキClojure

Clojureっていうじつに面白いプログラミング言語をとりあげていきます

インフォメーション

おすすめのイベント・勉強会情報を紹介

編集後記

vol.115

2015-Sep-13

Cover

前回と同じ開発合宿のショットから一つ

Vaqum Web Design Review

創刊以来延々と続くWebサイトレビュー

開発合宿へ行こう! : Python mini hack-a-thon 夏山合宿 2015

先週末に行ってきた開発合宿について書きました。

ミカヅキClojure

Clojureっていうじつに面白いプログラミング言語をとりあげていきます

インフォメーション

おすすめのイベント・勉強会情報を紹介

編集後記