Python入門講座:番外編¶

Statusbarアプリケーションを作る。¶

この講義では、macosxで 下の図のようにステータスバー(デスクトップメニューバーの右側の部分)に メニューを追加(この例では「mC」)するアプリケーションを作成する方法を紹介します。

mc_Menu

rumpsモジュールのインストール¶

このアプリケーションは、rumps(Ridiculously Uncomplicated MacOS Python Statusbar apps.)モジュールを使って作られています。rumpsモジュールはPyPIからダウンロード可能です。 pipコマンドを使ってインストールしましょう。

python3 -m pip install rumps

注: rumpsは3.9で動作を確認しています。3.10では、rumpsモジュール中の rumps.py ファイルで、

from collections import Mapping, Iterable

となっているところを、

from collections.abc import Mapping, Iterable

と書き換えておく必要があります。これは、python3の標準モジュールであるcollectionsモジュールの仕様が変更されたためです。なお、この変更はpython3.9で実施しても動作は変わりません。 3.11では、pythonと外部関数との接続のAPIが変更となったため、rumpsが必要とするpyobjc-coreモジュールを をpipでpython3.11にインストールすることができません。(pyobjcが更新されるのを待ちましょう。)

Jupyterlab ノートブックの中で pipインストールすることもできます。 次のセルのコメントを外して、セルを実行することで、rumpsモジュールがインストールされます。

In [1]:
# pip install -U rumps

rumpsを使ったモジュールの例¶

ここでは、二つの メニューアイテムを持つステータスバーのメニュ"mC"を作成する例を紹介します。 このアプリケーションでは、作成されたメニュー中のメニューアイテムを選択すると、それぞれに対応するシェルコマンドが実行されます。

In [2]:
#!python3
# coding: utf-8
from os import system
from rumps import App, MenuItem

myCommandList={
    'createTodaysPost' :  '~/bin/createTodaysPost.py',     
    'StartABlogViewer' :  '~/bin/StartABlogViewer.command',
}

class myApp(App ):
    def __init__(self, commandList):
        self.CommandList=commandList
        super(myApp, self).__init__("mC")
        self.menu=[
            MenuItem( k,
                      callback=self.exec_cmd)
            for k in commandList 
        ]
        
    def exec_cmd(self, sender):
        cmd=self.CommandList.get(sender.title, "")
        system(f"{cmd:s} &")

def main():
    myApp(myCommandList).run()

モジュールのインポート¶

from os import system
from rumps import App, MenuItem

このプログラムで利用するモジュール(osとrumps)をインポートしておきます。osモジュールからは、system関数。rumpsモジュールからは、AppクラスとMenuItemクラスをインポートします。

system関数は、指定したシェルコマンドを別プロセスの中で実行するための関数です。

Appはこれから作るアプリケーションの元になるクラス。MenuItemは作成するメニューアイテムを表現するためのrumpsのクラスです。

 作成するメニューの中身¶

作成するメニューの中身を指定するために、myCommandListを辞書型データとして定義します。このアプリケーションでは、メニューの項目毎に、 "項目名"と”実行するシェルコマンド名"が必要です。”項目名"から”シェルコマンド名"が容易に検索できるよう、辞書型データを使い、キーを"項目名"、値をシェルコマンド名としました。

myCommandList={
    'createTodaysPost' :  '~/bin/createTodaysPost.py',
    'StartABlogViewer' :'~/bin/StartABlogViewer.command',
}

アプリケーションクラスの定義と初期化¶

アプリケーションの本体となるクラスmyAppを定義します。myAppはrumpsのAppクラスを継承した子クラスとして定義します。

class myApp(App):
    def __init__(self, commandList):
        super(myApp, self).__init__("mC")
        self.CommandList=commandList
        self.menu=[
            MenuItem( k,
                      callback=self.exec_cmd)
            for k in commandList 
        ]

初期化¶

初期化では

  1. 親クラスの初期化ルーチンにメニューの名前を渡して、初期化を実行
  2. 初期化関数の引数として与えられた、commandListに従って、メニュアイテムオブジェクトのリストを作成し、
  3. myAppのmenuフィールドに設定

します。

メニュアイテムには、メニューアイテムの名前と、コールバック関数として、myAppの.exec_cmdメンバ関数を指定します。 

メニューアイテムのリストの作成には、python3のリストの内包表現(リスト コンプリヘンション)を使っています。

self.menu=[
            MenuItem( k,
                      callback=self.exec_cmd)
            for k in commandList 
        ]

Quit メニューアイテム¶

rumpsモジュールを使ったアプリケーションでは、Quitメニューアイテムは自動的に追加されます。

コールバック関数の定義¶

メニューアイテムのコールバック関数として使われた.exec_cmdは次の様に定義されています。

def exec_cmd(self, sender):
        cmd=self.CommandList.get(sender.title, "")
        system(f"{cmd:s} &")

rumpsのMenuItemで指定したコールバック関数には一つの引数senderが渡されます。このsender引数は、実行のために選択されたメニューアイテムのオブジェクトが渡されます。sender.titleは結局のところ選択されたメニューアイテムのメニュー名と同じことになります。これをキーにCommandListの値を取得し、別プロセスのシェルの中で実行します。実行するコマンド名に&を追加することで、コマンドの実行が, myAppの実行を妨げない様にしています。

また、self.CommandListから値を取り出す際に、.getメンバ関数を使うことで、どんな場合にもKeyError例外が発生しないようにしています。

main関数 の定義¶

作成したアプリケーションは、myAppのオブジェクトを作成して、その.rum()メンバ関数を呼び出すことで、 その実行が開始されます。

def main():
    myApp(myCommandList).run()

この定義は、もちろん

def main():
    app=myApp(myCommandList)
    app.run()

と等価です。

main関数の実行¶

いつものように、

if __name__ == "__main__":
  main()

としておくことで、作成したpythonプログラムファイルを直接実行することもできるようになります。

注: Jupyterlab内でこのプログラムを動作させた場合、メニューが表示されている間、Jupyterlabは該当セルが評価中のままになります。メニューでQuitを選択すると、Jupyterlabのカーネル自体までQuitされて、そのエラーメッセージが表示されます。

In [ ]:
if __name__ == "__main__":
  main()

最後に¶

ここでは、rumpsモジュールを使ったアプリケーションの作成の非常に簡単な場合を説明しました。簡単では、ありますが、この仕組みは私にとって便利なもので、とても重宝しています。

rumpsモジュールはここで紹介した以上の様々な機能を持っています。 rumpsモジュール ホームページでは、

rumpsは 簡単な設定ツールバーや起動メニューが必要なコンソールベースのプログラムのためのものです。

  • ノティフケーション センタを利用したアプリケーション
  • デーモンの制御あるいは別プログラムを起動する。
  • タイマに従ってWebAPIを通じて簡単な情報を更新する

といった用途に有用であるとしています。 ただし、

  • GUIを中心としたアプリケーションには向いていない

とのことです。

このrumpsモジュールを使ったアプリケーションを作成するために、webの記事:rumpsを使ってPythonで簡単にMacのメニューバーアプリを作るや rumpsモジュール ホームページ のドキュメントなどを参考としました。