注: 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モジュールがインストールされます。
# pip install -U rumps
ここでは、二つの メニューアイテムを持つステータスバーのメニュ"mC"を作成する例を紹介します。 このアプリケーションでは、作成されたメニュー中のメニューアイテムを選択すると、それぞれに対応するシェルコマンドが実行されます。
#!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
]
初期化では
commandListに従って、メニュアイテムオブジェクトのリストを作成し、myAppのmenuフィールドに設定します。
メニュアイテムには、メニューアイテムの名前と、コールバック関数として、myAppの.exec_cmdメンバ関数を指定します。
メニューアイテムのリストの作成には、python3のリストの内包表現(リスト コンプリヘンション)を使っています。
self.menu=[
MenuItem( k,
callback=self.exec_cmd)
for k in commandList
]
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例外が発生しないようにしています。
作成したアプリケーションは、myAppのオブジェクトを作成して、その.rum()メンバ関数を呼び出すことで、
その実行が開始されます。
def main():
myApp(myCommandList).run()
この定義は、もちろん
def main():
app=myApp(myCommandList)
app.run()
と等価です。
いつものように、
if __name__ == "__main__":
main()
としておくことで、作成したpythonプログラムファイルを直接実行することもできるようになります。
注: Jupyterlab内でこのプログラムを動作させた場合、メニューが表示されている間、Jupyterlabは該当セルが評価中のままになります。メニューでQuitを選択すると、Jupyterlabのカーネル自体までQuitされて、そのエラーメッセージが表示されます。
if __name__ == "__main__":
main()
ここでは、rumpsモジュールを使ったアプリケーションの作成の非常に簡単な場合を説明しました。簡単では、ありますが、この仕組みは私にとって便利なもので、とても重宝しています。
rumpsモジュールはここで紹介した以上の様々な機能を持っています。
rumpsモジュール ホームページでは、
rumpsは 簡単な設定ツールバーや起動メニューが必要なコンソールベースのプログラムのためのものです。
といった用途に有用であるとしています。 ただし、
とのことです。
このrumpsモジュールを使ったアプリケーションを作成するために、webの記事:rumpsを使ってPythonで簡単にMacのメニューバーアプリを作るや rumpsモジュール ホームページ のドキュメントなどを参考としました。