Virtual Earthを利用した地図アプリケーション(その3)

日経ソフトウェアの連載(作ってビックリ!Visual Basic, こだかかおる、2008年7、8月号)と同じことをVBではなくPythonでやろうと試みる。

  • 前回までに行ったこと
    • Virtual Earth APIを呼び出すHTMLファイルは、ダウンロードして使わせていただく

(ファイル名はve.html。http://itpro.nikkeibp.co.jp/article/MAG/20071120/287618/?ST=nsw#200808にあるファイルvb0808.lzhを展開する。)

    • wxPythonでアプリケーション化する。
    • 地図表示形式(絵、航空写真、ハイブリッド)をボタンによって切り替え可能にした。
    • ズームイン、アウトができるようになった。

7月号の記事では、マウスを地図上で動かすとポインタがある地点の緯度と経度を判別して値を表示する、というところまで解説している。それを実装しようとしたのだが、JavaScriptの値を持ってくる方法が分からず悩む...。PythonからJavaScriptへ値を渡せるが、逆ができない。現時点では方法が不明なのでこの問題は置いておく。

  • 今回行ったこと(8月号の記事の内容を実装)
    • ve.htmlファイルは8月号版を使う。
    • 2点間の経路表示を可能に?
    • 印刷用ボタンを設置

2点間の経路表示

パネルの下に用意してあるテキストボックスに任意の地名を入力して、"Get Route"ボタンを押すと地図上で経路を示してくれる。

MainFrame.pyに以下のメソッドを追加する。

    def OnGetRoute(self, event):
        TFrom = self.TxtFrom.GetValue()
        TTo = self.TxtTo.GetValue()
        buf = "javascript:getRoute('%s', '%s')" % (TFrom, TTo)
        self.ie.LoadUrl(buf)

2点の地名をテキストボックスから取得し、APIへ渡している。
例えば、Fromを渋谷、Toを新宿とすると、結果は下図になる。

絶対、間違っているだろ。何がおかしいのかな。

印刷用ボタンの設置

印刷用ボタンを置いただけ。まだ中身は作っていない。wxPythonデモを調べればどうやればよいかはすぐ分かるだろう。

現時点でのMainFrame.pyは以下の通り。

#!/bin/env python
# coding: utf-8 

import sys, os
import wx

# from ActiveX_IEHtmlWindow.py
if wx.Platform == '__WXMSW__':
    import wx.lib.iewin as iewin

# user library

class MainFrame(wx.Frame):       
    def __init__(self, id, title):
        width, height = 850, 600
        wx.Frame.__init__(self, id, title="Virtual Earth with wxPython",
                          size=wx.Size(width, height))

        self.current = os.path.join(os.getcwd(), "ve.html")

        # status bar
        self.sb = self.CreateStatusBar(2)
        self.sb.SetStatusWidths([-1, 150])
        self.sb.SetStatusText(self.current)

        # widgets on a panel
        Pan = wx.Panel(self, -1)

        self.ie = iewin.IEHtmlWindow(Pan, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE)
        self.ie.LoadUrl(self.current)
        self.Bind(iewin.EVT_StatusTextChange, self.OnStatusTextChange, self.ie)

        BtnRoad = wx.Button(Pan, -1, u"道路")
        BtnAerial = wx.Button(Pan, -1, u"航空写真")
        BtnHybrid = wx.Button(Pan, -1, u"ハイブリッド")
        BtnBirdseye = wx.Button(Pan, -1, u"概観図")
        BtnZoomOut = wx.Button(Pan, wx.ID_ZOOM_OUT)
        BtnZoomIn  = wx.Button(Pan, wx.ID_ZOOM_IN)
        BtnGetRoute = wx.Button(Pan, -1, "Get Route")
        BtnPrtWeb = wx.Button(Pan, -1, u"印刷(WebBrowser)")
        BtnPrt = wx.Button(Pan, -1, u"印刷")

        BtnRoad.Bind(wx.EVT_BUTTON, self.OnRoad)
        BtnAerial.Bind(wx.EVT_BUTTON, self.OnAerial)
        BtnHybrid.Bind(wx.EVT_BUTTON, self.OnHybrid)
        BtnBirdseye.Bind(wx.EVT_BUTTON, self.OnBirdseye)
        BtnZoomOut.Bind(wx.EVT_BUTTON, self.OnZoomOut)
        BtnZoomIn.Bind(wx.EVT_BUTTON, self.OnZoomIn)
        BtnGetRoute.Bind(wx.EVT_BUTTON, self.OnGetRoute)

        StTxt1 = wx.StaticText(Pan, -1, u"緯度:")
        StTxt2 = wx.StaticText(Pan, -1, u"経度:")
        StTxt3 = wx.StaticText(Pan, -1, u"ルート探索:")
        TxtLatitude = wx.TextCtrl(Pan, -1, "  ")
        TxtLongitude = wx.TextCtrl(Pan, -1, "  ")
        self.TxtFrom = wx.TextCtrl(Pan, -1, "", size=(200,-1))
        self.TxtTo = wx.TextCtrl(Pan, -1, "", size=(200,-1))

        # sizer
        Sizer0 = wx.BoxSizer(wx.VERTICAL)
        Sizer1 = wx.BoxSizer(wx.HORIZONTAL)
        Sizer3 = wx.BoxSizer(wx.HORIZONTAL)

        Sizer1.Add(BtnRoad, 0, wx.FIXED_MINSIZE|wx.LEFT, 2)
        Sizer1.Add(BtnAerial, 0, wx.FIXED_MINSIZE|wx.LEFT, 2)
        Sizer1.Add(BtnHybrid, 0, wx.FIXED_MINSIZE|wx.LEFT, 2)
        Sizer1.Add(BtnBirdseye, 0, wx.FIXED_MINSIZE|wx.LEFT, 2)
        Sizer1.Add(BtnZoomOut, 0, wx.FIXED_MINSIZE|wx.LEFT, 40)
        Sizer1.Add(BtnZoomIn, 0, wx.FIXED_MINSIZE|wx.LEFT, 2)
        Sizer1.Add(StTxt1, 0, wx.FIXED_MINSIZE|wx.LEFT, 20)
        Sizer1.Add(TxtLatitude, 0, wx.FIXED_MINSIZE|wx.LEFT, 2)
        Sizer1.Add(StTxt2, 0, wx.FIXED_MINSIZE|wx.LEFT, 10)
        Sizer1.Add(TxtLongitude, 0, wx.FIXED_MINSIZE|wx.LEFT, 2)

        Sizer3.Add(StTxt3, 0, wx.FIXED_MINSIZE|wx.LEFT, 2)
        Sizer3.Add(self.TxtFrom, 0, wx.FIXED_MINSIZE|wx.LEFT, 10)
        Sizer3.Add(self.TxtTo, 0, wx.FIXED_MINSIZE|wx.LEFT, 10)
        Sizer3.Add(BtnGetRoute, 0, wx.FIXED_MINSIZE|wx.LEFT, 10)
        Sizer3.Add(BtnPrtWeb, 0, wx.FIXED_MINSIZE|wx.LEFT, 40)
        Sizer3.Add(BtnPrt, 0, wx.FIXED_MINSIZE|wx.LEFT, 10)

        Sizer0.Add(Sizer1, 0, wx.ALL, 10)
        Sizer0.Add(self.ie, 1, wx.EXPAND)
        Sizer0.Add(Sizer3, 0, wx.ALL, 10)

        Pan.SetSizer(Sizer0)

    def mapStyle(self, style):
        buf = "javascript:setMapStyle('%s')" % style
        self.ie.LoadUrl(buf)

    def OnRoad(self, event):
        self.mapStyle('r')

    def OnAerial(self, event):
        self.mapStyle('a')

    def OnHybrid(self, event):
        self.mapStyle('h')

    def OnBirdseye(self, event):
        self.mapStyle('o')

    def OnZoomOut(self, event): 
        buf = "javascript:setZoomLevel(0)"
        self.ie.LoadUrl(buf)

    def OnZoomIn(self, event): 
        buf = "javascript:setZoomLevel(1)"
        self.ie.LoadUrl(buf)

    def OnGetRoute(self, event):
        TFrom = self.TxtFrom.GetValue()
        TTo = self.TxtTo.GetValue()
        buf = "javascript:getRoute('%s', '%s')" % (TFrom, TTo)
        self.ie.LoadUrl(buf)

    def OnStatusTextChange(self, event):
        #Maybe, I should do something here to obtain latitude and
        #longitude, but I have no idea how to do it now...
        pass
#        self.sb.SetStatusText("hoge")