Bing Maps上に地震の震源地を表示するプログラムを作る

2013年2月20日(水)
薬師寺 国安

<※前ページからの続きです。>

[現在の情報保存]ボタンがクリックされた時の処理

現在の、何年何月何日何時何分何秒.xmlという文字列を作成し、変数myFileに格納しておきます。

ピクチャライブラリ内のEarthQuakeDataというサブフォルダにアクセスします。CreateAsyncFolderメソッドにCreationCollisionOption.OpenIfExistsを指定してフォルダを作成すると、既に同名のフォルダがある場合は、そのフォルダ名を返し、無い場合はフォルダを新規に作成してくれます。

CreateFileAsyncメソッドでサブフォルダ内に変数myFileが格納しているファイルを作成し、変数saveFileで参照しておきます。

FileIO.WriteTextAsyncメソッドで、指定したファイルにmyResponse(結果XMLが入っている)の内容を書き込みます。「保存しました。」のメッセージを表示し、dataShowButtonを使用可能にします。
これで、現在の地震の情報を記録したXMLファイルが保存されます。非同期処理で行われるため、メソッドの先頭にAsyncを追加します。

01Private Async Sub dataSaveButton_Click(sender As Object, e As RoutedEventArgs) Handles dataSaveButton.Click
02  Dim myFile As String = DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & ".xml"
03  Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFoldersPicturesLibrary
04  Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("EarthQuakeData", CreationCollisionOption.OpenIfExists)
05  Dim saveFile As StorageFile = Await mySubFolder.CreateFileAsync(myFile)
06  Await FileIO.WriteTextAsync(saveFile, myResponse)
07 Dim myMessage As New MessageDialog("保存しました")
08  Await myMessage.ShowAsync
09  dataShowButton.IsEnabled = True
10End Sub

[過去のデータ一覧]ボタンをクリックした時の処理

Button表面の文字で条件分岐を行います。

Button表面の文字が「過去のデータ一覧」の場合の処理です。

非表示だったListBoxを表示します。ピクチャライブラリのEarthQuakeDataサブフォルダにアクセスします。
GetFileAsyncメソッドでEarhtQuakeDataサブフォルダ内のファイルを取得しコレクション変数DataFileに格納します。
文字列型の新しいリストであるmyFileオブジェクトを作成します。

ファイルを格納しているコレクション変数DataFile内のファイルを変数resultで取得しながら、反復処理を行います。
リストのオブジェクトmyFileにAddメソッドで、Path.GetFileNameWithoutExtension(result.Path)と指定して、取得したファイル名を、パスや拡張子を除いて追加していきます。
同じくリストであるメンバ変数myFile2にはパス付拡張子付のファイル名を追加していきます。

Button表面の文字が「現在のデータ表示」の場合は、ListBoxを非表示にし、Buttonの文字を「過去のデータ一覧」としてDataShowプロシージャを実行します。

非同期処理で行われるため、メソッドの先頭にAsyncを追加します。Asyncが追加されていると、その処理が非同期で行われることを意味します。

01Private Async Sub dataShowButton_Click(sender As Object, e As RoutedEventArgs) Handles dataShowButton.Click
02  Select Case dataShowButton.Content.ToString
03    Case "過去のデータ一覧"
04      ListBox1.Visibility = Xaml.Visibility.Visible
05      Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
06      Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("EarthQuakeData", CreationCollisionOption.OpenIfExists)
07      Dim DataFile As IReadOnlyList(Of StorageFile) = Await mySubFolder.GetFilesAsync()
08      Dim myFile As New List(Of String)
09 
10      For Each result In DataFile
11        myFile.Add(System.IO.Path.GetFileNameWithoutExtension(result.Path))
12        myFile2.Add(result.Path)
13      Next
14      ListBox1.ItemsSource = myFile
15      dataShowButton.Content = "現在のデータ表示"
16    Case "現在のデータ表示"
17      ListBox1.Visibility = Xaml.Visibility.Collapsed
18      dataShowButton.Content = "過去のデータ一覧"
19      DataShow()
20    End Select
21 
22End Sub

ListBoxから表示したい日付が選択された時の処理

Mapを一度初期化しておきます。この処理を怠ると円が重複して表示されますので、注意してください。
ピクチャライブラリのEarthQuakeDataサブフォルダにアクセスします。GetFileAsyncメソッドでEarthQuakeDataサブフォルダ内のファイルを取得し、コレクション変数readXmlFileに格納しておきます。
コレクション変数readXmlFileでListBoxから選択されたインデックスに該当するファイルを取得し、変数myTextに格納します。ドキュメントライブラリのEarthQuakeDataフォルダには図18のような形でXMLファイルが保存されています。

図18:ドキュメントライブラリのEarthQuakeDataサブフォルダに保存されているXMLファイル(クリックで拡大)

XElement.ParseメソッドでテキストとしてのXMLファイル(myText)を読み込みます。

地図の表示形式を「道路表示」とします。各変数をString.Emptyで初期化しておきます。

ListBoxから選択されたファイル名を、SubStringメソッドを使って、年、月、日の値を抽出します。/(スラッシュ)で連結して変数nenTukiHiに格納しておきます。

DescenDatnstメソッドで全ての子孫要素に対して、その値を変数resultに格納しながら、反復処理を行います。メンバ変数zIndexNo2の値を1ずつ加算します。

要素の各子要素の値を各変数に格納していきます。結果XMLの構造はリスト3を参照してください。

リスト3の結果XML内の、要素の子要素要素の子要素での子要素要素の子要素での子要素要素の値を使用します。

MapのCenterプロパティにDouble型に変換したmyLatitude(要素の値を格納)とmyLongitude(要素の値を格納)の値で初期化された、新しいLocationを指定します。

新しいEllipseのインスタンスmyEllipseオブジェクトを作成します。枠線の色をNavyに指定します。WidthとHeightは20とします。直径20pixelの円が描かれます。

新しいStackPanelのインスタンスmyStackpanelオブジェクトを作成します。SetValueメソッドのZindexPropertyに1ずつ加算されるzIndexNo2の値を指定します。StackPanelが円よりも前面に表示されます。myStackPanelオブジェクトの背景色にGainsBoroを指定します。初期状態ではmyStackPanelオブジェクトを非表示としておきます。

次に、TextBlockの新しいインスタンスmyTextBlockオブジェクトを作成します。パディングに5を指定し、Textプロパティに改行を含めた、「発生日時」、「震源地」、「マグニチュード」、「震度」を指定します。文字色はNavyで、文字サイズは20とします。
myStackPanelオブジェクトにmyTextBlockオブジェクトを追加します。

MapLayerクラスのSetPositionメソッドで、マップレイヤー内に要素の位置を設定します。この場合、myLatitudeとmyLongitudeの位置にmyStackPaneオブジェクトをセットします。MapLayerクラスは、地図上の要素の位置を保持しているマップレイヤーを表すクラスです。
MapにAddメソッドでmyStackPanelオブジェクトを追加します。

「発生日時が」の中に変数nenTukiHI(現在の日付)が含まれていた場合は、円をRedで塗りつぶします。それ以外はYellowで塗りつぶします。

MapLayerクラスのSetPositionメソッドで、マップレイヤー内に要素の位置を設定します。この場合、myLatitudeとmyLongitudeの位置にmyEllipse(円)オブジェクトをセットします。
MapにAddメソッドでmyEllipseオブジェクトを追加します。

円がタップされた時はmyStackPanelオブジェクトを表示します。「発生日時」、「震源地」、「マグニチュード」、「震度」の書かれたTextBlockが表示されます。
myStackPanelオブジェクトがタップされた時は、myStackPanelオブジェクトを非表示にします。「発生日時」、「震源地」、「マグニチュード」、「震度」の書かれたTextBlockも非表示になります。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。Asyncが追加されていると、その処理が非同期で行われることを意味します。

01  Private Async Sub ListBox1_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ListBox1.SelectionChanged
02    Try
03      myMap.Children.Clear()
04      Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFoldersPicturesLibrary
05      Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("EarthQuakeData", CreationCollisionOption.OpenIfExists)
06      Dim readXmlFile As IReadOnlyList(Of StorageFile) = Await mySubFolder.GetFilesAsync()
07      Dim myText As String = Await FileIO.ReadTextAsync(readXmlFile(ListBox1.SelectedIndex))
08      Dim doc As XElement = XElement.Parse(myText)
09  
10      myMap.MapType = MapType.Road
11  
12      Dim detectionDate As String = String.Empty
13      Dim myLocation As String = String.Empty
14      Dim myLatitude As String = String.Empty
15      Dim myLongitude As String = String.Empty
16      Dim myMagnitude As String = String.Empty
17      Dim myIntensity As String = String.Empty
18  
19      Dim myDateTimeStr = ListBox1.SelectedItem.ToString
20      Dim _year As String = myDateTimeStr.Substring(0, 4)
21      Dim _month As String = myDateTimeStr.Substring(5, 2)
22      Dim _day As String = myDateTimeStr.Substring(8, 2)
23      Dim nenTukiHi As String = _year & "/" & _month & "/" & _day
24  
25      For Each result In From c In doc.Elements("item") Select c
26        zIndexNo2 = zIndexNo2 + 1
27        myLocation = result.Element("epicenter_location_name").Value
28        detectionDate = result.Element("detection_date").Value
29        myLatitude = result.Element("epicenter_coor_lat").Value
30        myLongitude = result.Element("epicenter_coor_long").Value
31        myMagnitude = result.Element("magnitude").Value
32        myIntensity = result.Element("intensity").Value
33        myMap.Center = New Location(CDbl(myLatitude), CDbl(myLongitude))
34         
35        Dim myEllipse As New Ellipse
36        myEllipse.Width = 20
37        myEllipse.Height = 20
38        myEllipse.Stroke = New SolidColorBrush(Colors.Blue)
39  
40        Dim myStackPanel As New StackPanel
41        myStackPanel.SetValue(Canvas.ZIndexProperty, zIndexNo2)
42        myStackPanel.Background = New SolidColorBrush(Colors.Gainsboro)
43        myStackPanel.Visibility = Xaml.Visibility.Collapsed
44   
45        Dim myTextBlock As New TextBlock
46        myTextBlock.Padding = New Thickness(5)
47        myTextBlock.Text = "発生日時=" & detectionDate & vbCrLf & "震源地=" & myLocation & vbCrLf & "マグニチュード=" & myMagnitude & vbCrLf & "震度=" & myIntensity
48        myTextBlock.Foreground = New SolidColorBrush(Colors.Navy)
49        myTextBlock.FontSize = 20
50        myStackPanel.Children.Add(myTextBlock)
51  
52        MapLayer.SetPosition(myStackPanel, New Location(CDbl(myLatitude), CDbl(myLongitude)))
53        myMap.Children.Add(myStackPanel)
54   
55        Dim _myDate As DateTime = Date.Now
56        If detectionDate.Contains(nenTukiHi) = True Then
57          myEllipse.Fill = New SolidColorBrush(Colors.Red)
58        Else
59          myEllipse.Fill = New SolidColorBrush(Colors.Yellow)
60        End If
61        MapLayer.SetPosition(myEllipse, New Location(CDbl(myLatitude), CDbl(myLongitude)))
62        myMap.Children.Add(myEllipse)
63        AddHandler myEllipse.Tapped, Sub()
64                               myStackPanel.Visibility = Xaml.Visibility.Visible
65                             End Sub
66  
67        AddHandler myStackPanel.Tapped, Sub()
68                             myStackPanel.Visibility = Xaml.Visibility.Collapsed
69                          End Sub
70      Next
71    Catch
72      Exit Sub
73    End Try
74  End Sub
75End Class

地図の拡大縮小、表示モードの変更等はBing Mapsで自動的に処理されるため、コードを書く必要はありません。

今回はここまでです。ありがとうございました。

  • Bing Maps上に地震の震源地を表示するWindowsアプリ

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています