AA管理ツール SETZER ver0.02 公開
Download SETZER ver.0.02.zip
※最新版はhoehoeSoftに
wxPythonでブックマーク管理ツールを作ろう!
準備
今回作るプログラムは、あらかじめブックマークを手動でテキストファイルに書き込んでおき、それを読み込む、という形式をとります。
まずそのブックマークを書き込んだファイルを作りましょう。
- bookmark.ini
つかさのほえほえ日記 |http://d.hatena.ne.jp/tukasa1919/ はてなブックマーク |http://b.hatena.ne.jp/tukasa1919/ 2ちゃんねる サーバ負荷監視所 |http://ch2.ath.cx/ Google リーダー | http://www.google.com/reader/view/#overview-page PPx help | http://homepage1.nifty.com/toro/ppxhlp.html Twitter | http://twitter.com/ wxPythonリファレンス | http://wxwindowsjp.sourceforge.jp/docs/html/wx/wx26.htm#classref gmail | https://mail.google.com/mail 簡易AAエディタ | http://iranegi.s5.xrea.com:8080/2ch/aaedit/aaedit.php
"|"で区切っています。サイト名とurlが対になってます。これをスクリプトと同じフォルダにおくことで、ブックマークを読み込みます。
また、Migemoも使うので、それに関係するファイル(migemo.dll migemo.pyd Dict)も、同じフォルダに用意しておいてください。
では次に、このファイルを読み込むプログラムを作成します。
GUIを作る
まずはGUIを作るところからはじめましょう。
- Bookmark01.py
import wx class MyTxtFrm(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id) self.TxtCtr = wx.TextCtrl(self, -1) self.LBox = wx.ListBox(self, -1) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.TxtCtr, 0, wx.EXPAND) self.sizer.Add(self.LBox, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(1) self.sizer.Fit(self) class MyApp(wx.PySimpleApp): def OnInit(self): self.TxtFrm = MyTxtFrm(None, -1) self.TxtFrm.SetSize( (180, 200) ) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1 app = MyApp() app.MainLoop()
wxPythonでAA管理ツールをつくろう!第一回 GUIを作ると全く同じですので、詳しくはそこを参照してください。
リストを作る
次に、bookmark.iniを読み込み、サイト名とurlが対になった辞書を作り、サイト名のリストをセットします。
- Bookmark02.py
import wx class MyTxtFrm(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id) self.TxtCtr = wx.TextCtrl(self, -1) self.LBox = wx.ListBox(self, -1) bf = open("bookmark.ini") booklist = bf.readlines() booklist = map((lambda x: x.decode("shift-jis").strip()),booklist) booklist = map((lambda x: x.rsplit("|")),booklist) booklist = map((lambda x: tuple(x)),booklist) self.BookDict = {} for x in booklist: name = x[0].strip() url = x[1].strip() self.BookDict[name] = url self.site_list = self.BookDict.keys() self.LBox.Set(self.site_list) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.TxtCtr, 0, wx.EXPAND) self.sizer.Add(self.LBox, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(1) self.sizer.Fit(self) class MyApp(wx.PySimpleApp): def OnInit(self): self.TxtFrm = MyTxtFrm(None, -1) self.TxtFrm.SetSize( (180, 200) ) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1 app = MyApp() app.MainLoop()
辞書の作成
bf = open("bookmark.ini") booklist = bf.readlines() booklist = map((lambda x: x.decode("shift-jis").strip()),booklist) booklist = map((lambda x: x.rsplit("|")),booklist) booklist = map((lambda x: tuple(x)),booklist) self.BookDict = {} for x in booklist: name = x[0].strip() url = x[1].strip() self.BookDict[name] = url
まずは辞書を作るところから。"|"を区切り文字にして、サイト名とurlの対を取り出します。
次いで空の辞書self.BookDictを作り、サイト名をキーに。urlを値にして一つずつ登録します。
これで次のような辞書ができます。
{'つかさのほえほえ日記' : 'http://d.hatena.ne.jp/tukasa1919/', 'はてなブックマーク' : 'http://b.hatena.ne.jp/tukasa1919/', '2ちゃんねる サーバ負荷監視所' : 'http://ch2.ath.cx/', 'Google リーダー' : 'http://www.google.com/reader/view/#overview-page', 以下略}
リストボックスに登録
self.site_list = self.BookDict.keys() self.LBox.Set(self.site_list)
次に、この辞書からサイト名のリストを作ります。キーのリストをkeys()で作成して、それをListBoxにセットします。
これで見た目は完成です。
次に、カーソル移動とMigemoによるインクリメンタルサーチができるようにします。
カーソル移動とインクリメンタルサーチの追加(コピペ)
- Bookmark03.py
import wx,migemo,re migemo_object = None class IncrementalSearch: def __init__(self,pattern,list): self.pattern = pattern self.new_list = [] self.old_list = list def GetBackList(self): global migemo_object if migemo_object==None: migemo_object = migemo.Migemo('Dict\migemo-dict') re_pattern = migemo_object.query(self.pattern) try: migemo_re_object = re.compile(re_pattern, re.IGNORECASE) except re.error: return False for x in self.old_list: if migemo_re_object.search(x): self.new_list.append(x) return self.new_list class MyTxtFrm(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id) self.TxtCtr = wx.TextCtrl(self, -1) self.LBox = wx.ListBox(self, -1) bf = open("bookmark.ini") booklist = bf.readlines() booklist = map((lambda x: x.decode("shift-jis").strip()),booklist) booklist = map((lambda x: x.rsplit("|")),booklist) booklist = map((lambda x: tuple(x)),booklist) self.BookDict = {} for x in booklist: name = x[0].strip() url = x[1].strip() self.BookDict[name] = url self.site_list = self.BookDict.keys() self.LBox.Set(self.site_list) self.TxtCtr.Bind(wx.EVT_KEY_DOWN, self.OnKeyChar) self.TxtCtr.Bind(wx.EVT_TEXT,self.OnText) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.TxtCtr, 0, wx.EXPAND) self.sizer.Add(self.LBox, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(1) self.sizer.Fit(self) def OnKeyChar(self,event): key = event.GetKeyCode() if key == wx.WXK_ESCAPE: wx.Exit() elif key == wx.WXK_UP: count = self.LBox.GetCount() next = self.LBox.GetSelection() - 1 if next >= 0: self.LBox.SetSelection(next) else: self.LBox.SetSelection(count - 1) elif key == wx.WXK_DOWN: count = self.LBox.GetCount() next = self.LBox.GetSelection() + 1 if next < count: self.LBox.SetSelection(next) else: self.LBox.SetSelection(0) elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): fr = self.LBox.GetStringSelection() webbrowser.open(self.BookDict[fr]) wx.Exit() else: event.Skip() def OnText(self,event): word = self.TxtCtr.GetValue() isearch = IncrementalSearch(word,self.BookDict.keys()) try: new_list = isearch.GetBackList() except: return False if new_list: self.LBox.Set(new_list) self.LBox.SetSelection(0) else: event.Skip() event.Skip() class MyApp(wx.PySimpleApp): def OnInit(self): self.TxtFrm = MyTxtFrm(None, -1) self.TxtFrm.SetSize( (180, 200) ) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1 app = MyApp() app.MainLoop()
変更したのは以下の点です。
そして、
self.TxtCtr.Bind(wx.EVT_KEY_DOWN, self.OnKeyChar) self.TxtCtr.Bind(wx.EVT_TEXT,self.OnText)
を__ini__に付け足してます。
やってることはAA管理ツールのコードの流用です。wxPythonでAA管理ツールを作ろう!第六回 PyMigemoでインクリメンタルサーチあたりのコードから該当箇所をコピペしてます。
URLをデフォルトのブラウザで開く
いよいよラストです。
実際にブックマークをブラウザで開けるようにしましょう。変更点は、
- urlをデフォルトのブラウザで開くためにwebbrowserをインポート
- OnKeyCharのEnterの箇所
です。
- Bookmark04.py
import wx,migemo,re,webbrowser migemo_object = None class IncrementalSearch: def __init__(self,pattern,list): self.pattern = pattern self.new_list = [] self.old_list = list def GetBackList(self): global migemo_object if migemo_object==None: migemo_object = migemo.Migemo('Dict\migemo-dict') re_pattern = migemo_object.query(self.pattern) try: migemo_re_object = re.compile(re_pattern, re.IGNORECASE) except re.error: return False for x in self.old_list: if migemo_re_object.search(x): self.new_list.append(x) return self.new_list class MyTxtFrm(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id) self.TxtCtr = wx.TextCtrl(self, -1) self.LBox = wx.ListBox(self, -1) bf = open("bookmark.ini") booklist = bf.readlines() booklist = map((lambda x: x.decode("shift-jis").strip()),booklist) booklist = map((lambda x: x.rsplit("|")),booklist) booklist = map((lambda x: tuple(x)),booklist) self.BookDict = {} for x in booklist: name = x[0].strip() url = x[1].strip() self.BookDict[name] = url self.site_list = self.BookDict.keys() self.LBox.Set(self.site_list) self.TxtCtr.Bind(wx.EVT_KEY_DOWN, self.OnKeyChar) self.TxtCtr.Bind(wx.EVT_TEXT,self.OnText) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.TxtCtr, 0, wx.EXPAND) self.sizer.Add(self.LBox, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(1) self.sizer.Fit(self) def OnKeyChar(self,event): key = event.GetKeyCode() if key == wx.WXK_ESCAPE: wx.Exit() elif key == wx.WXK_UP: count = self.LBox.GetCount() next = self.LBox.GetSelection() - 1 if next >= 0: self.LBox.SetSelection(next) else: self.LBox.SetSelection(count - 1) elif key == wx.WXK_DOWN: count = self.LBox.GetCount() next = self.LBox.GetSelection() + 1 if next < count: self.LBox.SetSelection(next) else: self.LBox.SetSelection(0) elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): fr = self.LBox.GetStringSelection() webbrowser.open(self.BookDict[fr]) wx.Exit() else: event.Skip() def OnText(self,event): word = self.TxtCtr.GetValue() isearch = IncrementalSearch(word,self.BookDict.keys()) try: new_list = isearch.GetBackList() except: return False if new_list: self.LBox.Set(new_list) self.LBox.SetSelection(0) else: event.Skip() event.Skip() class MyApp(wx.PySimpleApp): def OnInit(self): self.TxtFrm = MyTxtFrm(None, -1) self.TxtFrm.SetSize( (180, 200) ) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1 app = MyApp() app.MainLoop()
elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): fr = self.LBox.GetStringSelection() webbrowser.open(self.BookDict[fr]) wx.Exit()
Enterを押したときに、サイト名に対応したurlを開くようにします。
- 選択しているサイト名をキーにして、urlを取り出し
- それをデフォルトのブラウザで開く
ということをしてるわけですね。
まとめ
要は、AA管理ツールの枠組みを使えば、
- 登録する辞書
- Enterを押した時の挙動
の二つをいじるだけで、いろんなことができるというわけです。
他に僕が思いついたのは、定型文の管理。あと、辞書をうまく作ることができれば、クリップボード履歴を監視するeClipみたいなのも作れますね。
wxPythonでAA管理ツールを作ろう!第七回 直前のウィンドウに貼り付け
あいさつ
つかさです。
今回は、直前までアクティブだったウィンドウにAAを貼り付けられるようにします。
スクリプト
- 新たにpyautoをインポートし
- Enterを押したときの挙動に「直前のウィンドウをアクティブにして」「貼り付け」を付け足してます
- AAlist08.py
import wx,os,migemo,re,pyauto migemo_object = None class MyPopupWindow(wx.PopupWindow): def __init__(self, parent, style): wx.PopupWindow.__init__(self, parent, style) self.st = wx.StaticText(self, -1,pos=(10,10)) def ChangeTxt(self,message,pos): self.st.SetLabel(message) sz = self.st.GetBestSize() gps = self.GetSize() self.SetDimensions(pos[0], pos[1], sz.width + 20 , sz.height + 20) self.Show(True) class IncrementalSearch: def __init__(self,pattern,list): self.pattern = pattern self.new_list = [] self.old_list = list def GetBackList(self): global migemo_object if migemo_object==None: migemo_object = migemo.Migemo('Dict\migemo-dict') re_pattern = migemo_object.query(self.pattern) try: migemo_re_object = re.compile(re_pattern, re.IGNORECASE) except re.error: return False for x in self.old_list: if migemo_re_object.search(x): self.new_list.append(x) return self.new_list class MyTxtFrm(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id) aa_list = os.listdir("AAList") self.AA_Dict = {} for x in aa_list: key = os.path.splitext(x)[0].decode("shift-jis") path = os.path.join("AAlist",x) self.AA_Dict[key] = path self.win = MyPopupWindow(self, wx.SIMPLE_BORDER) self.TxtCtr = wx.TextCtrl(self, -1) self.LBox = wx.ListBox(self, -1, choices = self.AA_Dict.keys()) self.TxtCtr.Bind(wx.EVT_KEY_DOWN, self.OnKeyChar) self.TxtCtr.Bind(wx.EVT_TEXT,self.OnText) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.TxtCtr, 0, wx.EXPAND) self.sizer.Add(self.LBox, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(1) self.sizer.Fit(self) def OnKeyChar(self,event): key = event.GetKeyCode() if key == wx.WXK_ESCAPE: wx.Exit() elif key == wx.WXK_UP: count = self.LBox.GetCount() next = self.LBox.GetSelection() - 1 if next >= 0: self.LBox.SetSelection(next) else: self.LBox.SetSelection(count - 1) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key == wx.WXK_DOWN: count = self.LBox.GetCount() next = self.LBox.GetSelection() + 1 if next < count: self.LBox.SetSelection(next) else: self.LBox.SetSelection(0) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): c_board = wx.Clipboard() f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() c_board.SetData(wx.TextDataObject(fr)) c_board.Flush() c_board.Close() pyauto.Input.send([ pyauto.KeyDown(pyauto.VK_MENU ), pyauto.Key(pyauto.VK_ESCAPE ), pyauto.KeyUp(pyauto.VK_MENU), pyauto.KeyDown(pyauto.VK_CONTROL), pyauto.Key(ord('V')), pyauto.KeyUp(pyauto.VK_CONTROL) ]) wx.Exit() else: event.Skip() def OnText(self,event): word = self.TxtCtr.GetValue() isearch = IncrementalSearch(word,self.AA_Dict.keys()) try: new_list = isearch.GetBackList() except: return False if new_list: self.LBox.Set(new_list) self.LBox.SetSelection(0) self.ShowToolTip() else: event.Skip() event.Skip() def ShowToolTip(self): f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) class MyApp(wx.PySimpleApp): def OnInit(self): self.TxtFrm = MyTxtFrm(None, -1) self.TxtFrm.SetSize( (180, 200) ) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1 app = MyApp() app.MainLoop()
キー操作
OnKeyCharの下の方を見てください。
pyauto.Input.send([ pyauto.KeyDown(pyauto.VK_MENU ), pyauto.Key(pyauto.VK_ESCAPE ), pyauto.KeyUp(pyauto.VK_MENU), pyauto.KeyDown(pyauto.VK_CONTROL), pyauto.Key(ord('V')), pyauto.KeyUp(pyauto.VK_CONTROL) ]) wx.GetApp().OnClose()
Enterを押したときの動作に、数行加えています。
クリップボードにAAテキストを入れた後、
- 直前のウィンドウをアクティブにして
- 貼り付け
という動作を追加してます。
まず、直前のウインドウをアクティブに。これは、Alt+Escで実現できますね。Alt+Tabしか知らなかったひとは試してみましょう^^
次の貼り付けは、Ctrl+Vでできます。
pyauto.Input.sendで、それに対応したキーを送ります。
- Altキーを押して→Escapeキーを一瞬押して離して→Altキーを離してから
- Ctrlキーを押して→Vキーを一瞬押して離して→Ctrlキーを離す
という感じですね。
wxPythonでAA管理ツールを作ろう!第六回 PyMigemoでインクリメンタルサーチ
あいさつ
つかさです。
今回は、PyMigemoを使います。
PyMigemoのインストール
migemo.pydと、migemo.dllをスクリプトのあるフォルダにおけば、このモジュールを使えるようになります。
また、migemo用のDictもどこかからダウンロードしましょう。これも同じフォルダにおきます。
migemoでパターンを得る
例えば、Migemoオブジェクトを作った後、query()にtukaというのを与えると
([捕遺仕疲遣柄攫束塚使冢掴閊障把支捉司掌元曹搏]|tuka|tuka|つか|付かぬ事|ツカ)
このようなパターンを得ることができます。
このパターンを正規表現に利用すれば、ローマ字でも日本語を検索できるわけです。
プログラム
以前から変更したのは大きくは二点。
- IncrementalSearchクラスを付け加えた
- OnKeyTxtを付け加えた
- AAlist07.py
import wx,os,migemo,re migemo_object = None class MyPopupWindow(wx.PopupWindow): def __init__(self, parent, style): wx.PopupWindow.__init__(self, parent, style) self.st = wx.StaticText(self, -1,pos=(10,10)) def ChangeTxt(self,message,pos): self.st.SetLabel(message) sz = self.st.GetBestSize() gps = self.GetSize() self.SetDimensions(pos[0], pos[1], sz.width + 20 , sz.height + 20) self.Show(True) class IncrementalSearch: def __init__(self,pattern,list): self.pattern = pattern self.new_list = [] self.old_list = list def GetBackList(self): global migemo_object if migemo_object==None: migemo_object = migemo.Migemo('Dict\migemo-dict') re_pattern = migemo_object.query(self.pattern) try: migemo_re_object = re.compile(re_pattern, re.IGNORECASE) except re.error: return False for x in self.old_list: if migemo_re_object.search(x): self.new_list.append(x) return self.new_list class MyTxtFrm(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id) aa_list = os.listdir("AAList") self.AA_Dict = {} for x in aa_list: key = os.path.splitext(x)[0].decode("shift-jis") path = os.path.join("AAlist",x) self.AA_Dict[key] = path self.win = MyPopupWindow(self, wx.SIMPLE_BORDER) self.TxtCtr = wx.TextCtrl(self, -1) self.LBox = wx.ListBox(self, -1, choices = self.AA_Dict.keys()) self.TxtCtr.Bind(wx.EVT_KEY_DOWN, self.OnKeyChar) self.TxtCtr.Bind(wx.EVT_TEXT,self.OnText) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.TxtCtr, 0, wx.EXPAND) self.sizer.Add(self.LBox, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(1) self.sizer.Fit(self) def OnKeyChar(self,event): key = event.GetKeyCode() if key == wx.WXK_ESCAPE: wx.Exit() elif key == wx.WXK_UP: count = self.LBox.GetCount() next = self.LBox.GetSelection() - 1 if next >= 0: self.LBox.SetSelection(next) else: self.LBox.SetSelection(count - 1) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key == wx.WXK_DOWN: count = self.LBox.GetCount() next = self.LBox.GetSelection() + 1 if next < count: self.LBox.SetSelection(next) else: self.LBox.SetSelection(0) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): c_board = wx.Clipboard() f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() c_board.SetData(wx.TextDataObject(fr)) c_board.Flush() c_board.Close() wx.Exit() else: event.Skip() def OnText(self,event): word = self.TxtCtr.GetValue() isearch = IncrementalSearch(word,self.AA_Dict.keys()) try: new_list = isearch.GetBackList() except: return False if new_list: self.LBox.Set(new_list) self.LBox.SetSelection(0) self.ShowToolTip() else: event.Skip() event.Skip() def ShowToolTip(self): f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) class MyApp(wx.PySimpleApp): def OnInit(self): self.TxtFrm = MyTxtFrm(None, -1) self.TxtFrm.SetSize( (180, 200) ) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1 app = MyApp() app.MainLoop()
IncrementalSearchクラス
検索文字列と調べたいリストを受け取り、検索文字列に一致したもののみのリストを返すIncrementalSearchクラスを作製しましょう。
class IncrementalSearch: def __init__(self,pattern,list): self.pattern = pattern self.new_list = [] self.old_list = list def GetBackList(self): global migemo_object if migemo_object==None: migemo_object = migemo.Migemo('Dict\migemo-dict') re_pattern = migemo_object.query(self.pattern) try: migemo_re_object = re.compile(re_pattern, re.IGNORECASE) except re.error: return False for x in self.old_list: if migemo_re_object.search(x): self.new_list.append(x) return self.new_list
__init__のところを見てください。引数として
- 検索に用いたい文字列
- その文字列で検索したいリスト
を受け取ります。
GetBackListは、受け取ったリストを受け取った文字列でmigemo検索し、それにヒットした要素のみを、新しいリストとして返す関数です。GetBackListについて説明します。
Migemoオブジェクトの作成
if migemo_object==None: migemo_object = migemo.Migemo('Dict\migemo-dict')
まず、Migemoオブジェクトがあるかどうかで分岐します。無い場合は、作製します。
一々オブジェクトを作ると、時間がかかるのでこのようにしています。
本体と結びつける
OnText関数
エディットボックスで何か入力されるたびにこのクラスを呼び出し、リストを受け取り、ListBoxにセットすればいいわけですね。
そのための関数OnTextを作製します。
def OnText(self,event): word = self.TxtCtr.GetValue() isearch = IncrementalSearch(word,self.AA_Dict.keys()) try: new_list = isearch.GetBackList() except: return False if new_list: self.LBox.Set(new_list) self.LBox.SetSelection(0) self.ShowToolTip() else: event.Skip() event.Skip()
GetValue()でエディットボックスの文字列を受け取ります。
次に、先に作ったIncrementalSearchにその文字列と、ファイル名のリストを投げます。
そして戻ってきた新しいリストをListBoxにセットし、ListBoxの一番上を選択した状態にし、ツールチップを表示します。
EVT_TEXTで結びつけ
ついで、これをエディットボックスと結びつけます。class MyTxtFrmの初期化メソッド__init__に、次の一文を付け加えます。
self.TxtCtr.Bind(wx.EVT_TEXT,self.OnText)
これで、エディットボックスに文字が入力されるたびに、OnText関数が呼び出されることになります。
インクリメンタルサーチの様子
wxPythonでAA管理ツールを作ろう!第八回 設定ファイル
あいさつ
つかさです。
今回は設定ファイルです。ConfigParserというモジュールを使います。
設定が必要なもの
まずは設定ファイルを作成しましょう。
- 大きさ(幅と高さ)
- 位置(x,y)
- ツールチップの色
あたりが、必要なものでしょうか。
以下のファイルを、スクリプトのあるフォルダに保存してください。
- aalist.ini
[DEFAULT] backgroundcolour = #B0E0E6 width = 200 height = 250 x = 400 y = 300
この設定ファイルを読み込み、反映するようにスクリプトを改造します。
- オブジェクトを作製
- iniファイルを読み込み
- read(セクション,値)で、個々の要素を取り出す
が一連の流れです。
スクリプト
ConfigParserというモジュールをインポートしてます。
- AAlist09.py
import wx,os,migemo,re,pyauto,ConfigParser migemo_object = None class MyPopupWindow(wx.PopupWindow): def __init__(self, parent, style, ini): wx.PopupWindow.__init__(self, parent, style) self.ini = ini b_color = self.ini.get( "DEFAULT", "BackgroundColour" ) self.SetBackgroundColour(b_color) self.st = wx.StaticText(self, -1,pos=(10,10)) def ChangeTxt(self,message,pos): self.st.SetLabel(message) sz = self.st.GetBestSize() gps = self.GetSize() self.SetDimensions(pos[0], pos[1], sz.width + 20 , sz.height + 20) self.Show(True) class IncrementalSearch: def __init__(self,pattern,list): self.pattern = pattern self.new_list = [] self.old_list = list def GetBackList(self): global migemo_object if migemo_object==None: migemo_object = migemo.Migemo('Dict\migemo-dict') re_pattern = migemo_object.query(self.pattern) print re_pattern try: migemo_re_object = re.compile(re_pattern, re.IGNORECASE) except re.error: return False for x in self.old_list: if migemo_re_object.search(x): self.new_list.append(x) return self.new_list class MyTxtFrm(wx.Frame): def __init__(self, parent, id, ini): wx.Frame.__init__(self, parent, id) aa_list = os.listdir("AAList") self.AA_Dict = {} for x in aa_list: key = os.path.splitext(x)[0].decode("shift-jis") path = os.path.join("AAlist",x) self.AA_Dict[key] = path self.win = MyPopupWindow(self, wx.SIMPLE_BORDER, ini) self.TxtCtr = wx.TextCtrl(self, -1) self.LBox = wx.ListBox(self, -1, choices = self.AA_Dict.keys()) self.TxtCtr.Bind(wx.EVT_KEY_DOWN, self.OnKeyChar) self.TxtCtr.Bind(wx.EVT_TEXT,self.OnText) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.TxtCtr, 0, wx.EXPAND) self.sizer.Add(self.LBox, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(1) self.sizer.Fit(self) def OnKeyChar(self,event): key = event.GetKeyCode() if key == wx.WXK_ESCAPE: wx.Exit() elif key == wx.WXK_UP: count = self.LBox.GetCount() next = self.LBox.GetSelection() - 1 if next >= 0: self.LBox.SetSelection(next) else: self.LBox.SetSelection(count - 1) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key == wx.WXK_DOWN: count = self.LBox.GetCount() next = self.LBox.GetSelection() + 1 if next < count: self.LBox.SetSelection(next) else: self.LBox.SetSelection(0) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): c_board = wx.Clipboard() f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() c_board.SetData(wx.TextDataObject(fr)) c_board.Flush() c_board.Close() pyauto.Input.send([ pyauto.KeyDown(pyauto.VK_MENU ), pyauto.Key(pyauto.VK_ESCAPE ), pyauto.KeyUp(pyauto.VK_MENU), pyauto.KeyDown(pyauto.VK_CONTROL), pyauto.Key(ord('V')), pyauto.KeyUp(pyauto.VK_CONTROL) ]) wx.Exit() else: event.Skip() def OnText(self,event): word = self.TxtCtr.GetValue() isearch = IncrementalSearch(word,self.AA_Dict.keys()) try: new_list = isearch.GetBackList() except: return False if new_list: self.LBox.Set(new_list) self.LBox.SetSelection(0) self.ShowToolTip() else: event.Skip() event.Skip() def ShowToolTip(self): f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) class MyApp(wx.PySimpleApp): def OnInit(self): self.INI_FILE = "aalist.ini" self.INI = ConfigParser.SafeConfigParser() self.INI.read(self.INI_FILE) self.width = self.INI.getint( "DEFAULT", "width" ) self.height = self.INI.getint( "DEFAULT", "height" ) self.x = self.INI.getint( "DEFAULT", "x" ) self.y = self.INI.getint( "DEFAULT", "y" ) self.TxtFrm = MyTxtFrm(None, -1, self.INI) self.TxtFrm.SetDimensions(self.x, self.y, self.width, self.height) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1 app = MyApp() app.MainLoop()
ウィンドウの位置と大きさ
class MyApp(wx.PySimpleApp): def OnInit(self): self.INI_FILE = "aalist.ini" self.INI = ConfigParser.SafeConfigParser() self.INI.read(self.INI_FILE) self.width = self.INI.getint( "DEFAULT", "width" ) self.height = self.INI.getint( "DEFAULT", "height" ) self.x = self.INI.getint( "DEFAULT", "x" ) self.y = self.INI.getint( "DEFAULT", "y" ) self.TxtFrm = MyTxtFrm(None, -1, self.INI) self.TxtFrm.SetDimensions(self.x, self.y, self.width, self.height) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1
MyAppの初期化の際に、
- 設定ファイルオブジェクトを作り
- 位置と大きさの値を取り出し
- TxtFrmに設定ファイルオブジェクトを引数として与える
ということをしてます。
self.INI_FILE = "aalist.ini"
self.INI = ConfigParser.SafeConfigParser()
self.INI.read(self.INI_FILE)
最初の三行で、ConfigParser.SafeConfigParser()でオブジェクトを作り、iniファイルを読み込ませてます。
self.width = self.INI.getint( "DEFAULT", "width" ) self.height = self.INI.getint( "DEFAULT", "height" ) self.x = self.INI.getint( "DEFAULT", "x" ) self.y = self.INI.getint( "DEFAULT", "y" )
次に、getintでそのオブジェクトから必要な値を取り出してます。
- 数字を取り出すならgetint
- 文字列を取り出すならget
です。
self.TxtFrm = MyTxtFrm(None, -1, self.INI) self.TxtFrm.SetDimensions(self.x, self.y, self.width, self.height)
そしてSetDimensionsで、ウィンドウを取り出した位置と大きさにセットしてるわけですね。
また、MyTxtFrmの引数としてself.INIを与えているのにも注意してください。
他のクラスでオブジェクトを利用
ツールチップ表示のためには、別のクラスでもINIファイルを読み込まなくてはいけません。ですが一々別のクラスでも、一々同じようにオブジェクトを作って、というのは面倒ですね。
そこで、一度作ったiniオブジェクトを、引数として各クラスに渡すようにしてます。
- MyFrmでオブジェクトを作り
- それをMyTxtFrmに引数として与え
- さらにMyTxtFrmからMyPopupWindowにオブジェクトを引数として与える
ということをしてます。
位置の記憶
終了時の大きさと位置を記憶し、起動時にはそこで表示したいという場合があると思います。それができるように、スクリプトを書き換えてみましょう。
その場合は、
- 終了する直前にiniオブジェクトを呼び出し
- writeで書き込む
そして起動したときには
- iniでその箇所を読み込む
というようにします。まずは設定ファイルを書き換えてください
- aalist.ini
[DEFAULT] backgroundcolour = #B0E0E6 width = 200 height = 250 x = 400 y = 300 historymode = 1 [HISTORY] width = 188 height = 238 x = 254 y = 278
DEFAULTセクションに、位置や大きさを記録するかどうかを決められるようhistorymodeを付け足してます。これが0なら記憶しない。1なら記憶するようにします。
スクリプト
MyAppの初期化のところで、前回の位置や記録を読み込むかどうかで分岐させてます
終了時に位置を記録するため、WriteIniとOnExitの二つの関数を付け足してます
- AAlist10.py
import wx,os,migemo,re,pyauto,ConfigParser migemo_object = None class MyPopupWindow(wx.PopupWindow): def __init__(self, parent, style, ini): wx.PopupWindow.__init__(self, parent, style) self.ini = ini b_color = self.ini.get( "DEFAULT", "BackgroundColour" ) self.SetBackgroundColour(b_color) self.st = wx.StaticText(self, -1,pos=(10,10)) def ChangeTxt(self,message,pos): self.st.SetLabel(message) sz = self.st.GetBestSize() gps = self.GetSize() self.SetDimensions(pos[0], pos[1], sz.width + 20 , sz.height + 20) self.Show(True) class IncrementalSearch: def __init__(self,pattern,list): self.pattern = pattern self.new_list = [] self.old_list = list def GetBackList(self): global migemo_object if migemo_object==None: migemo_object = migemo.Migemo('Dict\migemo-dict') re_pattern = migemo_object.query(self.pattern) print re_pattern try: migemo_re_object = re.compile(re_pattern, re.IGNORECASE) except re.error: return False for x in self.old_list: if migemo_re_object.search(x): self.new_list.append(x) return self.new_list class MyTxtFrm(wx.Frame): def __init__(self, parent, id, ini): wx.Frame.__init__(self, parent, id) aa_list = os.listdir("AAList") self.AA_Dict = {} for x in aa_list: key = os.path.splitext(x)[0].decode("shift-jis") path = os.path.join("AAlist",x) self.AA_Dict[key] = path self.win = MyPopupWindow(self, wx.SIMPLE_BORDER, ini) self.TxtCtr = wx.TextCtrl(self, -1) self.LBox = wx.ListBox(self, -1, choices = self.AA_Dict.keys()) self.TxtCtr.Bind(wx.EVT_KEY_DOWN, self.OnKeyChar) self.TxtCtr.Bind(wx.EVT_TEXT,self.OnText) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.TxtCtr, 0, wx.EXPAND) self.sizer.Add(self.LBox, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(1) self.sizer.Fit(self) def OnKeyChar(self,event): key = event.GetKeyCode() if key == wx.WXK_ESCAPE: wx.GetApp().OnExit() elif key == wx.WXK_UP: count = self.LBox.GetCount() next = self.LBox.GetSelection() - 1 if next >= 0: self.LBox.SetSelection(next) else: self.LBox.SetSelection(count - 1) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key == wx.WXK_DOWN: count = self.LBox.GetCount() next = self.LBox.GetSelection() + 1 if next < count: self.LBox.SetSelection(next) else: self.LBox.SetSelection(0) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): c_board = wx.Clipboard() f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() c_board.SetData(wx.TextDataObject(fr)) c_board.Flush() c_board.Close() pyauto.Input.send([ pyauto.KeyDown(pyauto.VK_MENU ), pyauto.Key(pyauto.VK_ESCAPE ), pyauto.KeyUp(pyauto.VK_MENU), pyauto.KeyDown(pyauto.VK_CONTROL), pyauto.Key(ord('V')), pyauto.KeyUp(pyauto.VK_CONTROL) ]) wx.GetApp().OnExit() else: event.Skip() def OnText(self,event): word = self.TxtCtr.GetValue() isearch = IncrementalSearch(word,self.AA_Dict.keys()) try: new_list = isearch.GetBackList() except: return False if new_list: self.LBox.Set(new_list) self.LBox.SetSelection(0) self.ShowToolTip() else: event.Skip() event.Skip() def ShowToolTip(self): f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) class MyApp(wx.PySimpleApp): def OnInit(self): self.INI_FILE = "aalist.ini" self.INI = ConfigParser.SafeConfigParser() self.INI.read(self.INI_FILE) if self.INI.getint( "DEFAULT", "HistoryMode" ) == 1: self.width = self.INI.getint( "HISTORY", "Width" ) self.height = self.INI.getint( "HISTORY", "Height" ) self.x = self.INI.getint( "HISTORY", "X" ) self.y = self.INI.getint( "HISTORY", "Y" ) else: self.width = self.INI.getint( "DEFAULT", "Width" ) self.height = self.INI.getint( "DEFAULT", "Height" ) self.x = self.INI.getint( "DEFAULT", "X" ) self.y = self.INI.getint( "DEFAULT", "Y" ) self.TxtFrm = MyTxtFrm(None, -1, self.INI) self.TxtFrm.SetDimensions(self.x, self.y, self.width, self.height) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1 def WriteINI(self): if self.INI.getint( "DEFAULT", "HistoryMode" ) == 1: x = str(self.TxtFrm.GetPosition()[0]) y = str(self.TxtFrm.GetPosition()[1]) width = str(self.TxtFrm.GetSize()[0]) height = str(self.TxtFrm.GetSize()[1]) self.INI.set('HISTORY','Width',width) self.INI.set('HISTORY','Height',height) self.INI.set('HISTORY','X',x) self.INI.set('HISTORY','Y',y) f = open(self.INI_FILE, "w") self.INI.write(f) f.close() else: return def OnExit(self): self.WriteINI() wx.Exit() app = MyApp() app.MainLoop()
前回の位置の読み込み
MyAppの初期化のところを見てください。
if self.INI.getint( "DEFAULT", "HistoryMode" ) == 1: self.width = self.INI.getint( "HISTORY", "Width" ) self.height = self.INI.getint( "HISTORY", "Height" ) self.x = self.INI.getint( "HISTORY", "X" ) self.y = self.INI.getint( "HISTORY", "Y" ) else: self.width = self.INI.getint( "DEFAULT", "Width" ) self.height = self.INI.getint( "DEFAULT", "Height" ) self.x = self.INI.getint( "DEFAULT", "X" ) self.y = self.INI.getint( "DEFAULT", "Y" )
前回の位置と大きさを読み込む設定になっていれば、HISTORYTセクションから読み込むように。なっていなければDEFAULTセクションで設定した値を読み込むようにしてます。
位置と大きさの記録
AAlist終了時には、OnExitを利用するようにします。AAlistを終了する時、というのは
- Escapeキーを押したとき
- Enterで貼り付けたとき
の二通りですね。それぞれ、今まではwx.Exit()で終了してたのを、wx.GetApp().OnExit()で新しく付け足した関数で終了するようにかえてます。
def WriteINI(self): if self.INI.getint( "DEFAULT", "HistoryMode" ) == 1: x = str(self.TxtFrm.GetPosition()[0]) y = str(self.TxtFrm.GetPosition()[1]) width = str(self.TxtFrm.GetSize()[0]) height = str(self.TxtFrm.GetSize()[1]) self.INI.set('HISTORY','Width',width) self.INI.set('HISTORY','Height',height) self.INI.set('HISTORY','X',x) self.INI.set('HISTORY','Y',y) f = open(self.INI_FILE, "w") self.INI.write(f) f.close() else: return def OnExit(self): self.WriteINI() wx.Exit()
DEFAULTセクションのhistorymodeの値をチェックし、前回の位置や大きさを記憶する設定であれば
- 現在のウィンドウの位置と大きさを取り出し
- それをINIオブジェクトにセットし
- INIファイルに書き込む
ということをします。
AA管理ツール SETZER ver0.01 公開
あいさつ
AA管理ツールが一応完成したので、公開します。
現在連載している「wxPythonでAA管理ツールを作ろう!」シリーズでは、九回目あたりで到達するであろうソースを使ってます。
直前までアクティブだったウィンドウに、選択したAAを貼り付けます。
Download SETZER ver.0.01.zip
※最新版はhoehoeSoftに
- 特徴
- ツールチップ表示
- AAをテキスト形式で管理
- 非常駐
- Migemoによるインクリメンタルサーチ
- 操作
- ウィンドウを閉じる→ESC
- アイテム選択→カーソルキー
- 選択アイテム貼り付け→Enter
wxPythonでAA管理ツールを作ろう!第五回 クリップボードに保存
あいさつ
つかさです。
今回は、クリップボードに選択したファイルの中身をコピーします。
クリップボード
MyTxtFrmクラスのOnKeyCharに、Enter用の分岐を付け加えてます。
- AAlist06.py
import wx,os class MyPopupWindow(wx.PopupWindow): def __init__(self, parent, style): wx.PopupWindow.__init__(self, parent, style) self.st = wx.StaticText(self, -1,pos=(10,10)) def ChangeTxt(self,message,pos): self.st.SetLabel(message) sz = self.st.GetBestSize() gps = self.GetSize() self.SetDimensions(pos[0], pos[1], sz.width + 20 , sz.height + 20) self.Show(True) class MyTxtFrm(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id) aa_list = os.listdir("AAList") self.AA_Dict = {} for x in aa_list: key = os.path.splitext(x)[0].decode("shift-jis") path = os.path.join("AAlist",x) self.AA_Dict[key] = path self.win = MyPopupWindow(self, wx.SIMPLE_BORDER) self.TxtCtr = wx.TextCtrl(self, -1) self.LBox = wx.ListBox(self, -1, choices = self.AA_Dict.keys()) self.TxtCtr.Bind(wx.EVT_KEY_DOWN, self.OnKeyChar) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.TxtCtr, 0, wx.EXPAND) self.sizer.Add(self.LBox, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(1) self.sizer.Fit(self) def OnKeyChar(self,event): key = event.GetKeyCode() if key == wx.WXK_ESCAPE: wx.Exit() elif key == wx.WXK_UP: count = self.LBox.GetCount() next = self.LBox.GetSelection() - 1 if next >= 0: self.LBox.SetSelection(next) else: self.LBox.SetSelection(count - 1) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key == wx.WXK_DOWN: count = self.LBox.GetCount() next = self.LBox.GetSelection() + 1 if next < count: self.LBox.SetSelection(next) else: self.LBox.SetSelection(0) f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() gps = self.GetSize() gp = self.GetPosition() pos = (gp.x + gps.x, gp.y + 45) self.win.ChangeTxt(fr,pos) elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): c_board = wx.Clipboard() f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() c_board.SetData(wx.TextDataObject(fr)) c_board.Flush() c_board.Close() wx.Exit() else: event.Skip() class MyApp(wx.PySimpleApp): def OnInit(self): self.TxtFrm = MyTxtFrm(None, -1) self.TxtFrm.SetSize( (180, 200) ) self.TxtFrm.Show() self.TxtFrm.TxtCtr.SetFocus() return 1 app = MyApp() app.MainLoop()
Enterを押したときの分岐
Enterを押せば、クリップボードに選択したファイルの中身をコピーし、終了するようにします。
Charの分岐にEnterを付け加えます。
elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): c_board = wx.Clipboard() f = open(self.AA_Dict[self.LBox.GetStringSelection()]) fr = f.read() c_board.SetData(wx.TextDataObject(fr)) c_board.Flush() c_board.Close() wx.Exit() else: event.Skip()
この箇所ですね。ListBoxで選択してるファイル名に対応したパスを、辞書を利用して取得し、その中身を取り出してクリップボードにセットしてます。
その後に、wx.Exit()でプログラムを終了しています。
次回の予定
これで、とりあえずはAA管理ツールとして一応は完成した、といってもいいのではないでしょうか。
次回はMigemoでインクリメンタルサーチができるようにする予定です