自作アプリに Google Map を表示させる(Google Mapからの通知受け)

Google MapはJavaScript上で勝手に動いてくれてますので地図を移動されようが、拡大・縮小されようが表示するだけならアプリ側では何もケアする必要はありません。ただ、少しアプリで何かしようとすると「勝手に動いてくれる処理」が邪魔になったりします。その辺り、Google Map側も身勝手ではないのできっかけは用意してくれてます。今回は最も基本となりそうな中心座標をアプリで取得してみようと思います。

中心座標を取得する切っ掛けを Google Maps API から発行してもらいます。というのも、Google Mapをマウスで掴んで素早くスクロールさせ離した場合、マウスは離した状態なのにMapは惰性でスルスルと動いているというケースがあるのでWebBrowserコントロールのクリックイベントのみでは止まった位置を把握する事が難しいからです。

Mapの移動が終わった時に発生するイベントは 'idle' です。ただしこの時点ではMap画像の読み込みは必ずしも終わっているわけではなく、そっちを捕まえたい場合は 'tilesloaded' を使用すると良いかもです(使った事無い)。以下の様にJavaScriptに記述すると'idle'のイベントが発生した時にこの関数読んでね的な事ができます。

map.addListener('idle', gm_event_idle);


gm_event_idle()はJavaScript内の関数(にしておく)なのでそこから一気にWindowのFormの関数を呼び出す様にします。これには、JavaScriptとWebbrowserコントロールとFormの連携が必要になってきます。window.external と WebBrowser.ObjectForScriptingプロパティ と 実行関数ですね。code.jsファイルは埋め込みリソースにしてgmap.htmlにキーワードを入れていてそこへ置換機能を使って展開しています。前回実施したのと同じ方法です。

code.js
function initMap() {


map.addListener('idle', gm_event_idle);


}

function gm_event_idle(){
var latlng = map.getCenter();
var str = latlng.lat() + "," + latlng.lng();
window.external.GMEvent_idle(str);
};


Form1.cs
[System.Runtime.InteropServices.ComVisible(true)]
public partial class Form1 : Form
{
private void FormMain_Load(object sender, EventArgs e)
{


this.webBrowser1.ObjectForScripting = this;


}


public void GMEvent_idle(string message)
{
string[] center = message.Split(',');
SetTextLatLong(double.Parse(center[0]), double.Parse(center[1]));
}

private void SetTextLatLong(double latitude, double longitude)
{
double fractional = latitude;
int integer = (int)fractional;
fractional -= integer;
string stInt = string.Format("{0,3:##0}", integer);
string stFrac = string.Format("{0:.0#############}", Math.Abs(fractional));
string st = stInt + stFrac;
this.maskedTextBoxLatitude.Text = st; // 緯度


fractional = longitude;
integer = (int)fractional;
fractional -= integer;
stInt = string.Format("{0,3:##0}", integer);
stFrac = string.Format("{0:.0#############}", Math.Abs(fractional));
st = stInt + stFrac;
this.maskedTextBoxLongitude.Text = st; // 経度
}



}


WebBrowser.ObjectForScriptingプロパティに設定するオブジェクトはComVisible属性を持つ必要があります。なので、class Form1 の直前に属性定義を記載しています。SetTextLatLong()の所でmaskedTextBoxコントロールに対して値を表示する様に設定しています。小数点の位置を保ちたかったのと、小数点第2位以下は0なら空白にしたかったのでチョッと変な変換を噛ましてます。

ビルドして実行した結果がこちらの動画です。
位置が決まると画像を読み込む前に緯度・経度を表示しているのと、画像を読み込む前に緯度・経度を表示しているのが見て取れると思います。


スポンサーサイト



tag : windows

tag : map

自作アプリに Google Map を表示させる(導入編 + APIキー隠蔽)

Google Mapは便利なので自作アプリ(Windows)で表示させてみたくなりました。Google Map側もこういった用途に合わせてAPIを用意してくれてます。ただし、完全無料とは行か無いです(アクセス数に応じて課金)。兎にも角にもチュートリアルを参考にマップを表示してみました。

先ずは、Google Maps Platformでアカウントを作成して、APIキーを生成し、そのキーで Maps JavaScript API にアクセスできるように設定しておいてください。設定方法は…結構変更されたりするのでここでは説明しません(参考)。

Maps JavaScript API tutorial に書かれているJavaScriptをWindowsのアプリで表示します。Google Mapのチュートリアルでは以下の(最低限必要な)内容(JavaScript)をブラウザで表示させれば良いとなってます。なので、この内容をファイル化してVisual Studio C#(.NET Framework)で表示すれば良いわけです。YOUR_API_KEY の部分は上記したAPIキーに置き換えてくださいね。

<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -34.397, lng: 150.644},
zoom: 8
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
async defer></script>
</body>
</html>


VSC#では WebBrower Control が有るのでこれに上記のファイルパスを指定して表示させれば出来上がり…と簡単には行かないのが現実。Google Mapを表示するにはIE10,11相当が必要らしいが、WebBrower Control のデフォルト設定がIE7相当になっているのが問題。WebBrower Controlをバージョンアップさせないと使えないです。バージョンアップといっても、コントロールを何処からかインストールする必要はなく、レジストリの値を書き換えるだけです(Internet Feature Controls (B..C))。

veiw_map_01.png

レジストリの書き換えには実行するプログラム名を使うようだけど、今後の事も考えて実行プロセスからファイル名を取得する様にしてみました。

var filePath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
var fileName = System.IO.Path.GetFileName(filePath);

Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION");
if (regKey != null)
{
// IE11
regKey.SetValue(fileName, 11001, Microsoft.Win32.RegistryValueKind.DWord);
regKey.Close();
}


後は WebBrower Control にHTMLのURI(絶対パス)を記載すればOK。なのですが、絶対パスなので不便です。そんな時に使う方法がexeのパスからの相対パスを保持しておいて、exeの絶対パスを割り出す事ですが、VSC#ってexeの絶対パスを取得するのが非常に面倒というか完全な正解を見つける事が出来なかったので、他の方法を使う事にしました。

HTMLファイルをexeに埋め込んじゃうのです。こうすれば環境依存のパスから解放されます。私はソリューションエクスプローラーの該当プロジェクト直下にhtmlというフォルダーを作成してその下にgmap.htmlというファイル名で管理しています。埋め込み方法はgmap.htmlを選択した時のプロパティウィンドウで「ビルドアクション」に「埋め込みリソース」を選択すればOKです。

veiw_map_02.png

埋め込んだリソースから内容を取得するには StreamReader() を使います。その引数に渡すStream内容を GetManifestResourceStream() で生成します。ここで埋め込んだリソースのパスが必要となってくるので、プロジェクト名とフォルダ名、ファイル名を '.' で繋いだ文字列を渡してやります。フォルダ名は作成していれば必要、階層を深くしていればそこまで全部 '.' で繋いで指定します。後は StreamReader.ReadToEnd() でファイルの中身をゴソリとstringに読み込ませて、WebBrower.DocumentTextプロパティに書き込めばHTMLを表示してくれちゃいます。

private void SetWebbrowserHtml()
{
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
string filePathName = "VeiwGMap.html.gmap.html";

using (System.IO.Stream stream = assembly.GetManifestResourceStream(filePathName))
{
if (stream != null)
{
using (System.IO.StreamReader sr = new System.IO.StreamReader(stream))
{
string gmap_html = sr.ReadToEnd();

this.webBrowser1.DocumentText = gmap_html;
}
}
}
}


veiw_map_03.png


exeに埋め込んだリソースってどうなっているか気になりますよね。ということで、バイナリエディタでチョッと拝見……、所詮埋め込みですから、まんま入ってます。ご丁寧にAPIキーも丸見えです。

veiw_map_04.png

対策方法はいろいろとありますが、表示前にstringに読み込んでいるという事を逆手に取ってAPIキーを別管理にしてしまう方法を取りました。こんな書き方をすると身構えてしまいますが、要は文字列の置換をするのです。HTML内ではAPIキーをユニークな文字列("YOUR_API_KEY")にしておきます。そして、リソースからstringに読み込んだ後、WebBrower.DocumentTextプロパティに書き込む前に string.Replace() を使って本来のAPIキーに書き換えるのです。

string gmap_html = sr.ReadToEnd();

gmap_html = gmap_html.Replace("YOUR_API_KEY", "aAbBcCdDeEfF0123456789");

this.webBrowser1.DocumentText = gmap_html;


上記のソースコードではプログラム中に直にAPIキーを記載していますが、string型渡せば良いので直前まで摩訶不思議な暗号化を噛ましておけば問題とならないでしょう。それと、この方法の副産物として、コンパイル後の実行ファイルのみでもAPIキーを入れ替えられる構成にできるという利点が生じます。

tag : windows

tag : map

黒ねこ時計 くろック D02
プロフィール

jujurou

Author:jujurou
運営HP:チャコの部屋
Twitter:jujurou

カレンダー
06 | 2020/07 | 08
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 -
最新記事
最新コメント
カテゴリ
ユーザタグ

ぺるけ Linux RaspberryPi 三段化 6P43P-E 全段差動プッシュプル トランジスタ式ミニワッター 6P43P TRminiWatterPart4 MPD FON2405E イーサネットコンバータ OpenOCD DAC buildroot FM3ペリフェラル BeagleBoneBlack map windows Bluetooth ODROID-U2 library FM3評価ボード mingw OpenGL シングル bitbake KiCad 計測 プリアンプ Edison VMware FM4 ミニワッター 6N6P TL-WR700N 

月別アーカイブ
ランキング

FC2 Blog Ranking

カウンター
検索フォーム
リンク
RSSリンクの表示
QRコード
QRコード
ライセンス
クリエイティブ・コモンズ・ライセンス
Twitter