Raspberry Pi から IRKitを操作するGUIを作ってみた。
一番簡単に作れそうとの理由で、PythonのTcl/Tk実装であるTkinterを使ってみた
これまでPythonプログラムでIRKit操作コマンドを作ってきました。(全然進みが遅いけど・・・)コマンドでの操作でもワタシは慣れているから良いけど、より一般的に使えるようにするにはGUIも欲しいよね。Pythonで一番簡単にGUI作るとしたら何だろうと思ってググッてみたら、PythonからTcl/Tkを使うTkinterってのが一番簡単そう。勉強と思って作り始めてみたのだけど、正直甘かった。Tkinterの入門的な日本語ホームページは色々見つかったのだけど、そこはやはり入門用。あまり深くは書いてなかったり、前程としてある程度Tcl/Tkの知識が必要で詳細はTcl/Tkのmanページを参照しなさいという感じだったりで、あちこちのホームページの記事をつまみ食いしながら作っていった感じ。Tkinterを網羅的に説明してくれている日本語のホームページか書籍が欲しいよぉ。
そんな訳で、まだ全然未完成で保存してある赤外線信号を送信するだけの機能しかないけど、何とか動くものはできましたので、備忘録として書いておこうと思います。
1. 今まで作ってきたIRKit操作コマンドをモジュールとして使えるようにする
GUIは今まで作ってきたIRKit操作コマンドに一皮被せたような感じにします。そのためIRKit操作コマンドをimportして使えるよう少し変えます。具体的にはimportした途端に argparse が動くと都合が悪いので、コマンドとして呼び出された時だけ argparse が動くようにしました。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
〜略〜
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Control IRKit')
parser.add_argument('-v', '--version', action='version', version='%(prog)s 0.2.1')
parser.add_argument('-V', '--verbose', action='store_true', default=False, help='verbose mode')
subparsers = parser.add_subparsers(dest='command')
# create the parser for the "get" command
parser_get = subparsers.add_parser('get', aliases=['read'], help='GET command')
parser_get.add_argument('ir_signal_name', action='store', help='IR signal name')
parser_get.add_argument('-a', '--address', nargs=1, action='store', default=None, dest='host',
metavar='address', help='IP address of IRKit device')
# create the parser for the "post" command
parser_post = subparsers.add_parser('post', aliases=['send'], help='POST command')
parser_post.add_argument('ir_signal_name', action='store', help='IR signal name')
parser_post.add_argument('-a', '--address', nargs=1, action='store', default=None, dest='host',
metavar='address', help='IP address of IRKit device')
# create the parser for the "show" command
parser_show = subparsers.add_parser('show', aliases=['view'], help='Show IR signal data')
parser_show.add_argument('ir_signal_name', action='store', help='IR signal name')
# create the parser for the "list" command
parser_list = subparsers.add_parser('list', help='Print list saved IR signal')
# create the parser for the "delete" command
parser_delete = subparsers.add_parser('delete', aliases=['remove'], help='Delete saved IR signal')
parser_delete.add_argument('ir_signal_name', action='store', help='IR signal name')
#
args = parser.parse_args()
verbose = args.verbose
else:
verbose = False
〜略〜
|
変更箇所は赤字の部分で、コマンドとして呼び出された時しか argpase を呼び出さないようにif文を入れています。これで importした時には argparse を呼び出さないはず。このように変更してファイル名"irkit_com.py"として保存しました。
2. GUIプログラム
次はGUIプログラムの方。先ずは簡単に、保存してあるjsonファイルの一覧を表示して、その中の一つを選んで送信するだけのGUIプログラムを作ってみました。先の "irkit_com.py" と同じフォルダに "irkit_gui.py" という名前で以下を保存します。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
from tkinter import *
from tkinter.messagebox import showerror, showinfo
from irkit_com import get_irkit_info, get, post # IRKit操作コマンド
save_dir = os.environ['HOME'] + '/' + '.irkit.d' # Getした赤外線信号の保存先ディレクトリ名
help_win = None
def help_window():
'''Help'''
global help_win
if help_win == None or not help_win.winfo_exists():
help_win = Toplevel() # ヘルプ用の新しいウィンドウを作る
help_win.title('IRKit Help') # ウィンドウのタイトル
help_text = '''IRKitの使用方法
IRKitメニュー
[GET...] 受信した赤外線信号を保存
[POST] 選択した赤外線信号を送信
[Quit] 終了
Helpメニュー
[Help...] ヘルプの表示
[About...] IRKitについて'''
msg = Message(help_win, text=help_text, width=320, justify='left')
msg.pack(side='left')
help_win.resizable(0, 0) # リサイズの禁止
def about_irkit():
'''About message'''
showinfo(title='about', message='IRKit GUI Ver.0.1.0')
def show_error(msg):
'''Print error message'''
showerror(title='IRKit error', message=msg)
class Application(Frame):
'''application class'''
def __init__(self, master):
master.title('IRKit') # ウィンドウのタイトル
master.minsize(240, 200) # ウィンドウサイズを制限
Frame.__init__(self, master, borderwidth=4, bg='#d0d0d0')
self.pack(expand=True, fill='both')
self.createMenu(master)
self.createWidgets()
def send_signal(self):
'''赤外線信号の送信'''
signame = self.lb.get('anchor')
if signame:
info = get_irkit_info()
address, port = info['IPaddress'], info['Port']
post(address, port, signame)
else:
show_error('赤外線信号が選択されていません')
def createMenu(self, master):
'''メニューの作成'''
# メニューバー
menubar = Menu(master)
master.config(menu=menubar)
# IRKitメニュー
irkit_menu = Menu(menubar, tearoff=False)
menubar.add_cascade(label='IRKit', underline=0, menu=irkit_menu)
# IRKitメニュー項目
irkit_menu.add_command(label='GET...', under=0, command=None) # 未作成
irkit_menu.add_command(label='POST', under=0, command=self.send_signal)
irkit_menu.add_separator()
irkit_menu.add_command(label='Quit', under=0, command=sys.exit)
# HELPメニュー
help_menu = Menu(menubar, tearoff=False)
menubar.add_cascade(label='Help', underline=0, menu=help_menu)
# HELPメニュー項目
help_menu.add_command(label='Help...', under=0, command=help_window)
help_menu.add_command(label='Abount...', under=0, command=about_irkit)
def createWidgets(self):
'''画面の作成'''
def post_signal(event):
self.send_signal()
# Listbox
self.lb = Listbox(self, width=40, height=10, selectmode=SINGLE, bd=4, relief=FLAT)
# Scrollbar
sb_y = Scrollbar(self, orient=VERTICAL, command=self.lb.yview)
self.lb.configure(yscrollcommand=sb_y.set)
# Listbox, ScrollbarをGridderで配置
self.lb.grid(column=0, row=0, sticky='news')
sb_y.grid(column=1, row=0, sticky='ns')
# リサイズ設定
self.grid_columnconfigure(index=0, weight=1)
self.grid_rowconfigure(index=0, weight=1)
# IR信号ファイルの一覧をListboxに表示
for file in sorted(os.listdir(save_dir + '/signals')):
if file[0] != '.':
self.lb.insert(END, os.path.splitext(file)[0])
# バインディングの設定
self.lb.bind('<Double-1>', post_signal)
def main():
root = Tk()
app = Application(master=root)
app.mainloop()
if __name__ == '__main__':
main()
|
例によって「¥」は実際には半角の「\」(バックスラッシュ)です。このプログラムを、UTF-8、改行コードLFで保存します。たった115行のプログラムなんですけど、いったい何日かかったことやら。Tcl/Tkの知識もないこともあって、やりたい事をどのように実現すれば良いのか調べるのにも、まともに動かない原因を調べるのにもすごく時間がかかりました。たぶん詳しい人から見たらボロボロのプログラムなんだろうなぁ・・・しかし、たった115行のプログラムで、それなりのGUIアプリが作れるってのはスゴイことでもありますね。
3. 動かしてみる
このプログラムを実行すると、Raspberry Pi (Linux)では
こんな具合になります。左のがメインウィンドウで、"~/.irkit.d/signals/"フォルダ配下に保存されているjsonファイルの一覧が表示されているだけのシンプルなものです。一覧から送信したい赤外線信号の名前を一つ選んでダブルクリックするか、
IRKitメニューから「POST」を選ぶと送信されます。メニュー項目には「GET...」がありますが、この機能は未実装です。
因に、このプログラムはMacのPython3上でも動いていて、MacOS X 10.9 (Mavericks)で動かすと、こんな感じになります。
MacOS X上ではちゃんとMacのルック&フィールに従った感じになるんですね。メニューはちゃんと画面上端のメニューバーに表示されますし、スクロールバーもMacのデザインのものになってます。また、Helpメニューには
何もしていないのに検索メニューが追加され、これがまたちゃんと機能しているようなのです。これはちょっとした驚きでした。
|