wxPythonでAA管理ツールを作ろう!第八回 設定ファイル

あいさつ

つかさです。
今回は設定ファイルです。ConfigParserというモジュールを使います。

設定が必要なもの

まずは設定ファイルを作成しましょう。

あたりが、必要なものでしょうか。
以下のファイルを、スクリプトのあるフォルダに保存してください。

  • 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の初期化の際に、

  1. 設定ファイルオブジェクトを作り
  2. 位置と大きさの値を取り出し
  3. 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オブジェクトを、引数として各クラスに渡すようにしてます。

  1. MyFrmでオブジェクトを作り
  2. それをMyTxtFrmに引数として与え
  3. さらにMyTxtFrmからMyPopupWindowにオブジェクトを引数として与える

ということをしてます。

位置の記憶

終了時の大きさと位置を記憶し、起動時にはそこで表示したいという場合があると思います。それができるように、スクリプトを書き換えてみましょう。

その場合は、

  1. 終了する直前にiniオブジェクトを呼び出し
  2. writeで書き込む

そして起動したときには

  1. 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の値をチェックし、前回の位置や大きさを記憶する設定であれば

  1. 現在のウィンドウの位置と大きさを取り出し
  2. それをINIオブジェクトにセットし
  3. INIファイルに書き込む

ということをします。