Qt Quickで地図をドラッグさせてみよう:キュートにクロプラ開発(3)(2/2 ページ)
Qt Quickを使った簡単なGoogle Mapsアプリを作成してみよう。Qt Quickデザイナでパーツを配置したり、地図をドラッグさせたりしよう
アプリケーション動作の実装
続いて、アプリケーションの動作を実装していきます。冒頭で紹介しました通り、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などでも最新情報の発信を行っている。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- 15秒に1人がダウンロードしたQTを利用するメリットは
リッチクライアントベンダ・インタビュー(14) スマートフォンなどのクロスプラットフォームのUI開発に活用されるQT。利用するメリットについて聞いた - Web技術でネイティブアプリを作れるTitanium
iPad/iPhone VS Androidに戸惑っているWebデザイナ/開発者のために、Web技術でネイティブアプリを作れるオープンソースの開発ツール「Titanium」を紹介し、その利点や使い方を連載で解説します - App Store登録もOK! JavaScriptで作るiPhoneアプリ
これ、俺ならこう使う(5) HTML+JavaScriptでiPhoneアプリをWebアプリ的に開発しつつ、App Storeで販売できてしまう一挙両得のハイブリッド手法でCoCoTwitter作りました - Flashでできる! Androidアプリ制作入門
iFlash ProやFlash Builderに拡張機能を追加して、Androidで動く簡単なAdobe AIRのアプリを作る方法を紹介します - Flash CS5のiPhoneアプリ変換機能は無駄にならない
D89クリップ(15) Flash CS5製とiPhone SDK製のアプリの違いや、Flash Lite 4.0などFlashプラットフォームのモバイル対応について、Flashのエバンジェリストに聞いた - HTML+JavaScriptでWindows 7デスクトップアプリ
楽しいWindows 7アプリ作成入門(3) Webアプリ開発者/デザイナでもできる、Windows 7のデスクトップアプリの概要・作り方を、具体的なコードとともに基礎から教えます