連載
» 2011年12月15日 00時00分 公開

Qt Quickで地図をドラッグさせてみようキュートにクロプラ開発(3)(2/2 ページ)

[亀田大輔,KDEユーザ会]
前のページへ 1|2       

アプリケーション動作の実装

 続いて、アプリケーションの動作を実装していきます。冒頭で紹介しました通り、Google Mapsを利用しますので、Google Mapsを表示するためのHTMLを用意します。

 Google Maps APIのサンプルから、map-simple.htmlのHTMLを持ってくるか、こちらからダウンロードしてください。

 そして、WebViewのurlでそのファイルを指定します。ここでは、map.htmlという名前で作成したものとして説明していきます。

 試しに実行してみると分かりますが、ズームボタンは利用できるものの、マウスをドラッグしても表示場所が移動しません。

 残念ながら、現在リリースされているバージョンに搭載されているWebViewでは、マウスのドラッグ時の動作は、自分で実装する必要があります。

 そこで、いい教材と割り切り、その部分を実装していきましょう。

QMLとWebViewで実行するJavaScriptの連携

 まず、マウスのドラッグでマップの移動を実現するために必要な機能を考えてみましょう。

 Google MapsのAPIを多少知っている必要がありますが、以下のような機能を実装することで、マップの移動ができるようになります。

  • (a) マップの中心座標を指定する機能
  • (b) マウスをクリックした座標を判定する機能
  • (c) マウスのドラッグに従って中心座標を変更する機能

 このうち、(a)は、Google Maps APIを実行する必要がありますので、JavaScriptのfunctionになります。ここでは、map.htmlに追記するものとしましょう。

 (b)はQMLのイベントハンドラを実装すればよさそうです。

 それでは、(c)を実装するにはどうすればいいでしょうか?

 (a)で実装するGoogle Maps APIを呼び出すfunctionの実行に加えて、マウスの位置をそのfunctionに渡す必要がありそうです。

 そのために利用するのが、WebViewのjavaScriptWindowObjectsというプロパティです。これを指定することで、JavaScriptからQtのオブジェクトを参照できます。

 それでは、javaScriptWindowObjectsプロパティを利用する手始めとして、Google Mapsを表示する際の最初の座標をQML側で指定するようにしてみましょう。

 WebViewを以下のように変更します。

WebView {				 // (14)
    id: map				 // (15)
    anchors.top: searchbox.bottom	 // (16)
    anchors.bottom: parent.bottom	 // (17)
    anchors.left: parent.left		 // (18)
    anchors.right: parent.right		 // (19)
    url: "map.html"			 // (20)
 
    javaScriptWindowObjects: QtObject {	 // (21)
        id: js				 // (22)
        WebView.windowObjectName: "qml"	 // (23)
        property real lat: 35.68	 // (24)
        property real lng: 139.76	 // (25)
    }
}

 (21)〜(25)が先ほど説明した、javaScriptWindowObjectsの記述です。(23)では、JavaScriptからオブジェクトを参照できるようにするために名前を指定しています。

 (24)と(25)が東京の緯度と経度の値を定数で記述しているものです。

 この値を参照するために、map.htmlのJavaScriptのinitialize()を以下のように変更します。

 window.qml.latとwindow.qml.lngというところが、先ほどのQMLで記述した値を参照しているところです。

function initialize() {
    var centerLatlng = new google.maps.LatLng(window.qml.lat, window.qml.lng); 
    var myOptions = {
      center: centerLatlng,
      zoom: 8,
      mapTypeId: google.maps.MapTypeId.ROADMAP,
    }
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);}

 QMLから、WebViewで実行するJavaScriptに値を渡す方法がお分かりいただけたかと思います。

マップの移動を実装する

 ここから、本題のマップの移動を実装していきます。

 マウスのドラッグでマップを移動させますので、マウスイベントを取得するためのMouseAreaが必要です。

 利用するイベントハンドラは、クリックしたときに実行されるonPressedと、マウスが移動したときに実行されるonPositionChangedです。

 onPositionChangedはマウスが移動したら常に実行されてしまいますので、MouseAreaのpressedプロパティの値をチェックして、ドラッグかどうかの判定を行います。

 それさえ分かれば、あとは座標計算を行い、Google Maps APIの仕様に合わせて値を調整するだけです。

 結果のコードは、以下のようになります。

WebView {
    ・・・省略・・・
    property int mapWidth: 256				 // (21)
    property int mapHeight: 256				 // (22)
    property int centerX: map.width / 2			 // (23)
    property int centerY: map.height / 2		 // (24)
 
    javaScriptWindowObjects: QtObject {			 // (25)
        id: js						 // (26)
        WebView.windowObjectName: "qml"			 // (27)
        property real lat: 35.68			 // (28)
        property real lng: 139.76			 // (29)
 
        property real diffX: 0				 // (30)
        property real diffY: 0				 // (31)
    }
 
    MouseArea {						 // (32)
        id: mArea					 // (33)
        anchors.fill: parent				 // (34)
 
        property real startX: 0				 // (35)
        property real startY: 0				 // (36)
 
        onPressed: {					 // (37)
            mArea.startX = mouse.x			 // (38)
            mArea.startY = mouse.y			 // (39)
        }
 
        onPositionChanged: {				 // (40)
            if(mArea.pressed) {				 // (41)
                js.diffX = (mouseX - mArea.startX)
                                     / map.mapWidth	 // (42)
                js.diffY = (mouseY - mArea.startY)
                                     / map.mapHeight	 // (43)
                map.evaluateJavaScript("goLatLng()")	 // (44)
 
                mArea.startX = mouse.x			 // (45)
                mArea.startY = mouse.y			 // (46)
            }
        }
    }
}

 ポイントとなるところを説明していきます。

 mapWidth、mapHeightはGoogle Mapsの地図の幅と高さです。Google Mapsでは、地図のサイズを、表示領域とは関係なく持っています。ここでは、zoomが8のときの値を固定値で指定しています。

 (38)と(39)で、マウスのクリックした位置を取得しています。(42)と(43)では、X方向とY方向のマウスの移動ピクセル数を取得し、地図のサイズに合わせた値に変換して、javaScriptWindowObjectsに追加したプロパティ、diffXとdiffYにセットしています。

 すでに説明した通り、WebViewで実行するJavaScriptでQMLの値を参照するためには、javaScriptWindowObjectsを介する必要がありますので、このように値をセットしています。

 (44)が、WebViewで実行されているJavaScriptのfunctionを実行する箇所です。goLatLng()がfunctionの名前です。このように、イベントハンドラからfunctionを呼び出すことで、WebViewの表示を変更することができるのです。

 呼び出している、goLatLng()は下記のようになります。このコードを、map.htmlに追加します。

 goLatLng()では、mapオブジェクトの中央座標を取得し、window.qml.diffXとwindow.qml.diffYを参照してQML側で求めた移動距離分だけ座標を変更し、新しい座標をセットし直しているだけです。

function goLatLng() {
    var centerPoint = map.getProjection().fromLatLngToPoint(map.center);
 
    var newCenterX = centerPoint.x - window.qml.diffX;
    var newCenterY = centerPoint.y - window.qml.diffY;
    window.qml.centerX = newCenterX;
    window.qml.centerY = newCenterY;
 
    var point = new google.maps.Point(newCenterX, newCenterY);
    var projection = map.getProjection();
    var latlng = projection.fromPointToLatLng(point);
    window.qml.lat = latlng.lat();
    window.qml.lng = latlng.lng();
    map.setCenter(latlng);
}

 実行すると、地図をドラッグできることをご確認いただけるはずです。

実行した画面

まとめ

 今回は、Google Maps APIを使ったアプリケーションの開発について説明しました。

 実行してみた方はお気付きかと思いますが、この時点のコードには1つ問題があります。それは、ズームができなくなったことです。

 MouseAreaを WebView全体に対応付けたため、ズームボタンに対するクリックイベントも、このMouseAreaが受けてしまうためです。

 それでは、どうすればいいでしょうか?

 MouseAreaを一部だけくりぬくようなことはできませんので、自前のズームボタンを、WebViewの上に置くしかなさそうです。

 とはいえ、これ以上要素を付け足すことを考えると、だいぶ地図の部分だけ複雑になってきます。

 そこで、次回は、Mapコンポーネントとして、新たに独自のコンポーネントを作成するところからご説明していきます。

著者プロフィール

亀田大輔

亀田大輔

1978年12月6日生まれ。ユーザインターフェイスに惹かれてKDEを使い始め、KDEユーザ会のスタッフに加わる。それ以降、KDE/Qtの日本語入力関係の開発を中心に活動をし、2003年度の未踏事業にてQtの言語入力フレームワーク(module for Qt)の開発を行う。 現在は、日本KDEユーザー会の会長として活動し、ブログTwitterなどでも最新情報の発信を行っている。


前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。