Virtual Earthを利用した地図アプリケーション(その1)
日経ソフトウェアの記事で、Visual Basicで地図アプリケーションを作るものがある(作ってビックリ!Visual Basic, こだかかおる、pp.130、2008年7月号)。
同じことを、Visual Basicの代わりにwxPythonでやってみる。Virtual EarthのAPIを使って、WebアプリではなくWindowsフォームアプリケーションを作成する。
世界中に地図情報を提供するサービスである、Microsoft Virtual EarthのAPIは公開されている。wxPythonで作るので、Linuxでも使えるアプリになるはずだ。でもとりあえずWindowsでやってみる。
- ポイント整理
- Virtual Earth APIを使う。
- Virtual Earth APIはJavaScriptから使用するようになっている。
- JavaScriptは今まで使ったことない。
- VBではなく、wxPythonで作成する。
APIを呼び出しているファイルve.html(p.132のリスト1)は、JavaScriptを記述したHTMLファイルであり、これはこのまま使わせていただく。日経ソフトウェアのウェブページからダウンロードできたので、それを使う。
http://itpro.nikkeibp.co.jp/article/MAG/20071120/287618/?ST=nsw#200807のvb0807.lzhをダウンロードして展開。
とりあえず、このファイルを読み込んで、日本地図を表示するところまでwxPythonで作成した。
ソースは、_main_tree.pyとMainFrame.pyから成る。同じディレクトリにve.htmlを置いておく。
#!/bin/env python # _main_tree.py # coding: utf-8 import os, sys import wx import MainFrame class Application(wx.App): def OnInit(self): frame = MainFrame.MainFrame(None, -1) frame.Show(True) self.SetTopWindow(frame) return True def main(): import time app = Application(0) print u"info> このアプリケーションの起動時刻は %sです。" % time.ctime(time.time()) appl_boot_path = os.getcwd() print u"info> 起動ディレクトリは %sです。" % appl_boot_path app.MainLoop() if __name__ == '__main__': main() #eof
HTMLファイルを読み込むところは、wxPythonのデモコードのActiveX_IEHtmlWindow.pyを参考にした。Sizerの設定をうまくやらないと地図をパネルにうまく表示できない。
#!/bin/env python # MainFrame.py # coding: utf-8 import sys, os import wx # from ActiveX_IEHtmlWindow.py if wx.Platform == '__WXMSW__': import wx.lib.iewin as iewin class MainFrame(wx.Frame): def __init__(self, id, title): width, height = 850, 600 wx.Frame.__init__(self, id, title=u"Virtual Earth with wxPython", size=wx.Size(width, height)) self.current = os.path.join(os.getcwd(), "ve.html") # status bar sb = self.CreateStatusBar(2) sb.SetStatusWidths([-1, 150]) 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) 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") 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, " ") TxtFrom = wx.TextCtrl(Pan, -1, "", size=(300,-1)) TxtTo = wx.TextCtrl(Pan, -1, "", size=(300,-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(TxtFrom, 0, wx.FIXED_MINSIZE|wx.LEFT, 10) Sizer3.Add(TxtTo, 0, wx.FIXED_MINSIZE|wx.LEFT, 10) Sizer3.Add(BtnGetRoute, 0, wx.FIXED_MINSIZE|wx.LEFT, 40) Sizer0.Add(Sizer1, 0, wx.ALL, 10) Sizer0.Add(self.ie, 1, wx.EXPAND) # this is a point! Sizer0.Add(Sizer3, 0, wx.ALL, 10) Pan.SetSizer(Sizer0) def mapStyle(): pass 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): pass def OnZoomIn(self, event): pass def OnGetRoute(self, event): pass
_main_tree.pyをダブルクリックすれば実行され、下の画面が開く。
ここまでは良い。ボタンを押したときのイベントの実行をどうするか次に考える。
- 問題点
- HTMLファイル中に定義されたJavaScriptの関数(この場合、ve.htmlの中のsetMapStyleという関数)をファイルの外から呼ぶにはどうしたらいいのか?