HOME | Python | 書き込む |
Python には Tkinter, PyQt, PyGTK, wxPython などの gui toolkit があります。 いろいろと物色した結果次のことが分かりました。
01: #! usr/bin/env python 02: 03: r""" 04: script to achive photos in the removal media into HD 05: gui version using wxPython 06: by T.Shido 07: January 22, 2005 08: """ 09: import sys, os, shutil, filecmp, wx, wx.lib.dialogs 10: import photo as ph 11: from datetime import date 12: 13: class Aphoto(wx.App): 14: def OnInit(self): 15: ph.Search_Media(ph.MEDIA) 16: frame = wx.Frame(None) 17: self.SetTopWindow(frame) 18: pt = ph.sum([len(val) for val in ph.PHASH.itervalues()]) 19: 20: if pt: 21: dlg = wx.ProgressDialog("Sending Photos", \ 22: ("0/%d" % pt), \ 23: maximum = pt, \ 24: parent=frame, \ 25: style = wx.PD_AUTO_HIDE | wx.PD_APP_MODAL) 26: failed = self.Move_Photos(pt, dlg) 27: if failed: # if exist photos failed to archive 28: fdlg = wx.lib.dialogs.ScrolledMessageDialog(frame, failed, \ 29: "Copy Failed for these Photos: Try Again!") 30: fdlg.ShowModal() 31: 32: dlg.Destroy() 33: os.execl(ph.PHOTO_VIEWER, ph.PHOTO_VIEWER, self.pd0) 34: frame.Destroy() 35: return True 36: 37: else: 38: dlg = wx.MessageDialog(frame, 'No Photos in the media!', \ 39: 'Warning', \ 40: wx.OK | wx.ICON_INFORMATION ) 41: dlg.ShowModal() 42: dlg.Destroy() 43: sys.exit() 44: 45: def Move_Photos(self, pt, dlg): 46: md = ph.HD + date.today().strftime("%y-%m/") 47: np = ph.nPdir(md) 48: sf = 0 49: failed_log = '' 50: i0 = True 51: 52: os.chdir(md) 53: 54: for d, fs in ph.PHASH.iteritems(): 55: np += 1 56: pd = md + "photo%02d" % np 57: if i0: 58: self.pd0 = pd 59: i0 = False 60: os.mkdir(pd) 61: for f in fs: 62: f1 = d + f 63: f2 = pd + '/' + f 64: shutil.copyfile(f1, f2) 65: if filecmp.cmp(f1, f2): 66: os.remove(f1) 67: else: 68: failed_log += "copy failed: %s => %s\n" % (f1, f2) 69: sf += 1 70: dlg.Update(sf, ("%d/%d" % (sf, pt))) 71: return failed_log 72: #----------- 73: 74: if __name__ == '__main__': 75: Aphoto(redirect=False)
行 | 説明 |
---|---|
09 | wx, wx.lib.dialog をインポートする。 |
10 | 以前作ったコンソール版をインポートする。 python は perl に比べてスクリプトの再利用がしやすい。 photo.py は同じディレクトリにあるか、 PYTHONPATH の通ったディレクトリにあることが必要。 |
13 | wx.App を親クラスとしてクラス Aphotoを定義する。 |
14 | OnInit はwx.App クラス(のサブクラス)を初期化する時に実行される。 |
15 | メディアをサーチする。 |
16 | wx.Frame のインスタンス frame を作る。 このスクリプトでは、ダイアログボックスを出すだけだが、 ダイアログボックスの親フレームとして必要。 |
17 | frame を topwindow にする。 |
18 | メディアにある画像ファイルの枚数を計算する。 |
20 | もし、メディアに画像ファイルがあれば、 |
21 | プログレスダイアログを作る。 |
21,22 | 最初の引数はプログレスダイアログのタイトル、2番目の引数は表示される文字。 |
23 | プログレスダイアログのゲージの最大値を画像ファイルの枚数に設定。 |
24 | 親フレームは frame |
25 | 表示スタイルの設定。終了後自動的に消えるようにする。 |
26 | メディアからハードディスクに画像を移動する。 返り値は移動できなかった画像ファイルのリストの文字列 |
27 | もし、移動できなかった画像ファイルがあれば、スクロールメッセージダイアログを開く |
32 | プログレスダイアログを閉じる。 |
33 | 閲覧ソフトを起動させる。 |
34 | frame を閉じる。 |
35 | OnInt は真偽値を返す必要がある。 |
37 | もし、メディアに画像ファイルがなければ、その旨のメッセージダイアログを表示する。 |
45 | 画像ファイルを移動させるメソッドの定義 |
70 | 画像ファイルを1枚移動させるたびにダイアログをアップデートする。 |
75 | redirect=False にしておくとエラーメッセージなどはコンソール (DOS prompt) に表示される。デバッグのときに便利。 |
photo.py
01: #! usr/bin/env python 02: 03: r""" 04: script to achive photos in the removal media into HD 05: by T.Shido 06: January 12, 2005: 10/27/12 07: """ 08: 09: from __future__ import nested_scopes 10: import glob, string, os, os.path, shutil, filecmp, re, sys 11: from datetime import date 12: 13: __all__ = ['Move_Photos', 'HD', 'MEDIA', 'PHOTO_VIEWER', 'PREGEXP'] 14: 15: # global parameters 16: HD = 'D:/doc/' 17: MEDIA = 'G:/' 18: PHOTO_VIEWER = 'D:/WBIN/linar160/linar.exe' 19: PREGEXP = re.compile(".(gif|bmp|jpe?g|tiff?)$", re.I) 20: 21: # functions 22: def sum(ls): 23: total = 0 24: for x in ls: 25: total += x 26: return total 27: 28: def nPdir(dir): 29: lst = [ x for x in glob.glob(dir + "photo[0-9][0-9]") if os.path.isdir(x)] 30: return lst and int(lst[-1][-2:]) or 0 31: 32: def Search_Media(dir): 33: """search Media and returns a hash 34: whose keys are directory name and the values are lists of photo files.""" 35: def search_sub(dir): 36: os.chdir(dir) 37: items = os.listdir(dir) 38: ls = [x for x in items if PREGEXP.search(x)] 39: if ls: 40: hash[dir] = ls 41: for d in [dir + x + '/' for x in items if os.path.isdir(x)]: 42: search_sub(d) 43: hash={} 44: search_sub(dir) 45: return hash 46: 47: def on_empty(): 48: """called by Move_Photos if media is empty.""" 49: print "No photos in the media: give return" 50: sys.stdin.readline() 51: sys.exit() 52: 53: def on_error(f1, f2): 54: """called by Move_Photos when filecopy is failed.""" 55: print "copy failed: %s => %s\n" % (f1, f2) 56: 57: def on_progress(sf, pt): 58: """called by Move_Photos during coping files.""" 59: print "%d/%d\r" % (sf, pt), 60: 61: def Move_Photos(on_progress, on_empty, on_error, on_start, on_end): 62: r""" 63: Moveing photo files from media into HD, 64: This function takes five parameters. 65: 1. pointer to function called during file copy 66: 2. pointer to function called if the media is empty 67: 3. pointer to function called when copyfile is failed 68: 4. pointer to function called before coping 69: 5. pointer to function called after coping 70: """ 71: md = HD + date.today().strftime("%y-%m/") 72: np = nPdir(md) 73: hash = Search_Media(MEDIA) 74: pt = sum([len(val) for val in hash.itervalues()]) 75: sf = 0 76: i0 = True 77: 78: if not pt: 79: on_empty() 80: 81: if on_start: 82: on_start(pt) 83: 84: if not os.path.isdir(md): 85: os.mkdir(md) 86: 87: os.chdir(md) 88: 89: for d, fs in hash.iteritems(): 90: np += 1 91: pd = md + "photo%02d" % np 92: if i0: 93: pd0 = pd 94: i0 = False 95: os.mkdir(pd) 96: for f in fs: 97: f1 = d + f 98: f2 = pd + '/' + f 99: shutil.copyfile(f1, f2) 100: if filecmp.cmp(f1, f2): 101: os.remove(f1) 102: else: 103: on_error(f1, f2) 104: sf += 1 105: on_progress(sf, pt) 106: 107: if on_end: 108: on_end() 109: 110: os.execv(PHOTO_VIEWER, [' ', pd0]) 111: 112: if __name__=='__main__': 113: Move_Photos(on_progress, on_empty, on_error, None, None)61 行目で Move_Photos を5つの関数を引数にとる関数として定義しています。また、Search_Media は Move_Photos が呼び出すようにしています。つまり、photo を import するスクリプトは Move_Photos だけを使えば良いようになっています。
photo_wx.py
01: #! usr/bin/env python 02: 03: r""" 04: script to achive photos in the removal media into HD 05: gui version using wxPython 06: by T.Shido 07: January 22, 2005 08: """ 09: import photo as ph 10: import sys, wx, wx.lib.dialogs 11: 12: class Aphoto(wx.App): 13: def OnInit(self): 14: self.frame = wx.Frame(None) 15: self.SetTopWindow(self.frame) 16: ph.Move_Photos(self.on_progress, self.on_empty, self.on_error, self.on_start, self.on_end) 17: self.pdlg.Destroy() 18: frame.Destroy() 19: return True 20: 21: def on_start(self, total): 22: self.failed_log = '' 23: self.pdlg = wx.ProgressDialog("Sending Photos", \ 24: ("0/%d" % total), \ 25: maximum = total, \ 26: parent=self.frame, \ 27: style = wx.PD_AUTO_HIDE | wx.PD_APP_MODAL) 28: 29: def on_progress(self, count, total): 30: self.pdlg.Update(count, ("%d/%d" % (count, total))) 31: 32: def on_error(self, f_from, f_to): 33: self.failed_log += "copy failed: %s => %s\n" % (f_from, f_to) 34: 35: def on_empty(self): 36: dlg = wx.MessageDialog(self.frame, 'No Photos in the media!', \ 37: 'Warning', \ 38: wx.OK | wx.ICON_INFORMATION ) 39: dlg.ShowModal() 40: dlg.Destroy() 41: sys.exit() 42: 43: def on_end(self): 44: if self.failed_log: # if exist photos failed to archive 45: fdlg = wx.lib.dialogs.ScrolledMessageDialog(self.frame, self.failed_log, \ 46: "Copy Failed for these Photos: Try Again!") 47: fdlg.ShowModal() 48: 49: if __name__ == '__main__': 50: Aphoto(redirect=False)Move_Photos を呼び出しているのは、16 行目です。21--47 行目で Move_Photos に与える 5 つの 関数を定義しています。
関数 | 説明 |
---|---|
on_start | プログレスダイアログを作成します。 |
on_progress | プログレスダイアログを更新します。 |
on_error | 移動に失敗したファイル名を記録します。 |
on_empty | メディアが空の場合、その旨を表示するダイアログを作成します。 |
on_end | 移動に失敗したファイルがある場合、それを表示するダイアログを作成します。 |
HOME | Python | 書き込む |