Pythonバッチにお飾り curses メニュー

Pythonバッチにお飾り curses メニュー

前置き

Pythonバッチにお飾りGUIに引き続き「UIをさぼる」ネタ。

サボるのが目的であるから、あくまで不真面目に取り組む。

curses でやりたくなること、案外多い。いわゆる「サーバ機」のリモート保守、みたいなことを考える。この場合、保守プログラムを構築するには VPN でもあてに出来ない限りは自ずと選択肢が限られて、WEB ベースのものを作りこむか、telnet (ssh) クライアント経由で CUI か。

お飾りメニュー駆動バッチの仕様

  • 10個のメニューアイテムから選べるだけでいい
  • 日本語はいらない
  • メニューからユーザが選択したら画面クリアして目的のことをする
  • 目的のことの出力が終わったらキー入力待ちする
  • キー入力があったらメニューに戻る

Pythonバッチにお飾りGUI同様、仕様というよりは願望。これだけで出来てしまうことは限られるが、「これでいいならそれでいい」。

ファイルのダイジェストを取るだけの

ただの例です。本気でこの目的でこんなことするヤツはいない。

 1 import sys
 2 import curses
 3 
 4 def _menu(screen, menu_title, items):
 5     # 日本語は出来ないことはないようだが、頑張りすぎると不毛なので割り切ったほうがいい。
 6     # Windowsのことまで考えると border などの装飾はやめたほうがいい。ガッカリするはず。
 7     curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_WHITE)
 8     screen.keypad(1)
 9     pos = 0
10     x = None
11     hn = {
12         True: curses.color_pair(1) | curses.A_BOLD,
13         False: curses.A_NORMAL
14         }
15     while x != ord('\n'):
16         screen.clear()
17         screen.addstr(2, 2, menu_title, curses.A_STANDOUT)
18         for i, item in enumerate(items):
19             screen.addstr(4 + i, 4,
20                           "{} - {}".format(i, item),
21                           hn[pos == i])
22         x = screen.getch()
23         if x in [ord(str(i)) for i in range(len(items))]:
24             pos = x - ord('0')
25         # http://blog.skeltonnetworks.com/tag/python-curses/ で
26         # curses.KEY_* が効かない、と困っていたが、ワタシの環境では
27         # 使えた。なんだろうね?
28         elif x == curses.KEY_DOWN:  #258:
29             pos = (pos + 1) % len(items)
30         elif x == curses.KEY_UP:  #259:
31             pos = (len(items) + pos - 1) % len(items)
32         elif x != ord('\n'):
33             curses.flash()
34     return items[pos]
35 
36 def main(screen, fn):
37     import hashlib
38     filecontents = open(fn, "rb").read()
39 
40     curses.start_color()
41     title = "hashlib"
42     menuitems = [
43         'md5',
44         'sha1',
45         'sha224',
46         'sha256',
47         'sha384',
48         'sha512',
49         'Exit',
50         ]
51     while True:
52         selection = _menu(screen, title, menuitems)
53         if selection == "Exit":
54             break
55         if sys.platform == "win32":
56             import os
57             os.system("cls")
58         else:
59             sys.stdout.write("\x1b[2J\x1b[H")
60         digester = hashlib.new(selection)
61         digester.update(filecontents)
62         print(digester.hexdigest())
63         screen.getch()
64 
65 if __name__ == '__main__':
66     import locale
67     locale.setlocale(locale.LC_ALL, '')
68     curses.wrapper(main, sys.argv[1])

参考にしたサイト

随分前に、本当にこれに近いことを仕事でやったことはあったが、それ以来やっていなかったので、あちこち参考にした。

基本コードベースは Python Curses – Custom Menu|Programming ThoughtsCode Project: Build an Ncurses UI with Python

画面クリアはなんだか皆苦労しているようで、clear terminal in python|stackoverflowより。

Snake ゲームはまぁお約束ですな。

本気の curses の入り口としては
[python]プロトタイプをcursesで|DoRuby!が良いかも。チャットプログラムを作ってる。

ネタとして面白いのは Python Curses Example of Dungeon-Building Algorithm

NetHack作れるぞ。

curses Windows版

Windows版にも curses モジュールそのものは存在している。ただ、curses 本体は、自分でインストールしないと使えない。

setuptoolsはインストール済み、として、

1 me@host: ~$ easy_install pip
2 me@host: ~$ pip install wheel

http://www.lfd.uci.edu/~gohlke/pythonlibs/#curses より curses-2.2-cp27-none-win_amd64.whl (等貴方の環境に合ったもの)を入手、

1 me@host: ~$ pip install curses-2.2-cp27-none-win_amd64.whl

これで Python の curses が使えるようになる。

2021-03-29追記

まず、Windows 版 curses については、最近は(?)「windows-curses」パッケージがある:

1 me@host: ~$ py -3 -m pip install windows-curses

最初に書いたときからあったのかもしれないけど、少なくとも今はこれで入手出来るので、こちらをどぞ。

あと、ちょっと個人的に「シンプルなデジタル時計」がご入用だったので、ちょいとご気楽に作ってみたのがあるので、ご賞味どぞー(要: pillow):

「curses 事始め」にはちょうどいい気がしたの。

2021-04-03更に追記

一つ上のサンプルと大差はないんだけれど、こういうのをやりたい、て人は割といる気がするんで一応(要psutil):

「Unix の df の(簡易)ビジュアライズ」ね。