Liby's Blog

 汝鬼耶,抑人耶?

Archive for the ‘Qt’ tag

Windows平台下Qt5.1 for Android的安卓开发环境

with 13 comments

前段时间Qt5.1正式版发布,支持Android和IOS的开发,强大的可移植性和跨平台特性非常的吸引人,并且使用C++。由于之前做过Qt在嵌入式平台的应用,所以顺便试试新版本的Qt如何,再看看Qt5.1 for Android是否足够优秀呢,环境搭建如下,可能会有疏漏之处。
整个配置过程可以参考官方Wiki
首先是各种软件的下载,先不管目前对开发有没有用吧,整上再说,包括Perl、Mingw等等。
Perl
MSYS
MinGW
Ant
JDK
NDK
SDK
Qt5.1 for Android

有些版本可能会有更新,根据自己的情况下载需要的版本。我最终下载的文件名如下(文件顺序与上对应):
strawberry-perl-5.16.3.1-32bit.msi
msys+7za+wget+svn+git+mercurial+cvs-rev13.7z
x32-4.8.1-release-win32-dwarf-rev3.7z
apache-ant-1.9.2-bin.zip
jdk-7u25-windows-i586.exe
android-ndk-r9-windows-x86.zip
adt-bundle-windows-x86-20130729.zip
qt-windows-opensource-5.1.0-android-x86-win32-offline.exe

各个文件解压或则安装,现在需要设置一下环境变量。我先说一下我的文件路径如下(路径顺序与上对应):
C:\strawberry
C:\mingw-builds\msys
C:\mingw-builds\mingw32
C:\apache-ant-1.9.2
C:\Program Files\Java\jdk1.7.0_25
C:\android-ndk-r9
C:\adt-bundle-windows-x86-20130729
C:\Qt\Qt5.1.0

现在来设置环境变量,所有操作全部在环境变量中的系统变量里面。
增加变量名JAVA_HOME,变量值C:\Program Files\Java\jdk1.7.0_25
增加变量名CLASSPATH,变量值.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\toos.jar
修改变量名Path,增加变量值C:\strawberry\perl\bin;%JAVA_HOME%\bin;C:\mingw-builds\mingw32\bin;C:\adt-bundle-windows-x86-20130729\sdk\platform-tools;C:\adt-bundle-windows-x86-20130729\sdk\tools;C:\android-ndk-r9;

这样环境变量也就设置完了,测试下是否可用,CMD下分别输入以下命令是否发生错误:
java -version
javac -version
gcc -v
emulator -version
adb -version
mingw32-make -version

然后是Qt的设置如下图:

Qt5.1 performance

至于SDK Manager的相关内容在这不多说了,至此你可以开始C++开发Android应用了!

————————

2013.8.15

经过目前测试NDK暂时无法使用r9版本(当然,不排除是我的环境问题),会出现Qt无法自动找到构建工具的情况,虽然可以编译也可以在模拟器上运行,但是无法生成APK。如下图:

kit

主要原因如上图,路径不正确,正确路径应该是”\prebuilt\winodws\bin”。
不论是添加“ANDROID_NDK_HOST=windows”环境变量,还是手动添加构建套件Kit都无法解决问题。前者将如下一张图中ANDROID_NDK_HOST的值变为空值,手动修改无效;后者会导致Qt版本和编译器出错。
使用android-ndk-r8e-windows-x86.zip则正常,暂且不知道原因,但是应该和NDK的环境变量有关,一切参考官方WIKI为准。至于官方文档提到的

Add some environment variables:
set “ANDROID_NDK_PLATFORM=android-9”
set “ANDROID_TARGET_ARCH=armeabi-v7a”
set “ANDROID_BUILD_TOOLS_REVISION=17.0.0”
set “ANDROID_NDK_HOST=windows-x86_64”
or
set “ANDROID_NDK_HOST=windows”
.. depending on which NDK you downloaded.

可以尝试不添加,我使用android-ndk-r8e-windows-x86.zip这个NDK并且设置好NDK路径以后,Qt自动添加变量,但不会在系统环境变量中修改。如下图:

environment

可以生成APK,可以安装运行,如下图:

Screenshot_2013-08-15-14-33-17

Written by liby

八月 13th, 2013 at 3:30 下午

Posted in 技事巧事

Tagged with , ,

Google Maps API 代码示例

without comments

之前在Qt上做过一个关于Google Map相关程序,用到了Google Maps API,下面是一个示例样本,有很多不尽之处,仅供参考。

<html>
<head>
<style type="text/css">
    div#map_canvas
    {
    	position:relative;
    }
    div#crosshair
    {
    	position:absolute;
    	top:50%;
    	height:19px;
    	width:19px;
    	left:50%;
    	display:block;
    	margin-left:-8px;
    	background:url(crosshair.gif);
    	background-repeat:no-repeat;
    	background-position:center;
    	}
	#panel {
	position:absolute;
	top:5px;
	left:50%;
	width:536px;
	margin:0 0 0 -268px;
	}

</style>
<link href="/maps/documentation/javascript/examples/default.css" rel="stylesheet">
<script type="text/javascript" src="http://map.google.com/maps/api/js?sensor=false&language=zh-cn&libraries=panoramio"></script>
<script src="https://ssl.panoramio.com/wapi/wapi.js?v=1"></script>
<script type="text/javascript">
  var map;
  var geocoder;
  var addressresults;
  var lastrelease;
  var lastcenter;
  var maker;
  var markers = [];
  var directionsDisplay;
  var directionsService = new google.maps.DirectionsService();
  var start;
  var end;

/**
* The HomeControl adds a control to the map that
* returns the user to the control's defined home.
*/

// Define a property to hold the Home state
HomeControl.prototype.home_ = null;

// Define setters and getters for this property
HomeControl.prototype.getHome = function() {
return this.home_;
}

HomeControl.prototype.setHome = function(home) {
this.home_ = home;
}

/** @constructor */
function HomeControl(controlDiv, map, home) {

  // We set up a variable for this since we're adding
  // event listeners later.
  var control = this;

  // Set the home property upon construction
  control.home_ = home;

  // Set CSS styles for the DIV containing the control
  // Setting padding to 5 px will offset the control
  // from the edge of the map
  controlDiv.style.padding = '5px';

  // Set CSS for the control border
  var goHomeUI = document.createElement('div');
  goHomeUI.style.backgroundColor = 'white';
  goHomeUI.style.borderStyle = 'solid';
  goHomeUI.style.borderWidth = '2px';
  goHomeUI.style.cursor = 'pointer';
  goHomeUI.style.textAlign = 'center';
  goHomeUI.title = 'Click to set the map to Home';
  controlDiv.appendChild(goHomeUI);

  // Set CSS for the control interior
  var goHomeText = document.createElement('div');
  goHomeText.style.fontFamily = 'Arial,sans-serif';
  goHomeText.style.fontSize = '12px';
  goHomeText.style.paddingLeft = '4px';
  goHomeText.style.paddingRight = '4px';
  goHomeText.innerHTML = '<b>Home</b>';
  goHomeUI.appendChild(goHomeText);

  // Set CSS for the setHome control border
  var setHomeUI = document.createElement('div');
  setHomeUI.style.backgroundColor = 'white';
  setHomeUI.style.borderStyle = 'solid';
  setHomeUI.style.borderWidth = '2px';
  setHomeUI.style.cursor = 'pointer';
  setHomeUI.style.textAlign = 'center';
  setHomeUI.title = 'Click to set Home to the current center';
  controlDiv.appendChild(setHomeUI);

  // Set CSS for the control interior
  var setHomeText = document.createElement('div');
  setHomeText.style.fontFamily = 'Arial,sans-serif';
  setHomeText.style.fontSize = '12px';
  setHomeText.style.paddingLeft = '4px';
  setHomeText.style.paddingRight = '4px';
  setHomeText.innerHTML = '<b>Set Home</b>';
  setHomeUI.appendChild(setHomeText);

  // Setup the click event listener for Home:
  // simply set the map to the control's current home property.
  google.maps.event.addDomListener(goHomeUI, 'click', function() {
    var currentHome = control.getHome();
    map.setCenter(currentHome);
  });

  // Setup the click event listener for Set Home:
  // Set the control's home to the current Map center.
  google.maps.event.addDomListener(setHomeUI, 'click', function() {
    var newHome = map.getCenter();
    control.setHome(newHome);
  });
}

  function initialize() {

    directionsDisplay = new google.maps.DirectionsRenderer();

    var  myLatlng = new google.maps.LatLng(30.3363695555555,112.215555555555);

    var myOptions = {
    zoom: 17,//缩放比例
    center: myLatlng,//设置地图中心为myLatlng
    disableDefaultUI: true,
    mapTypeControl: true,//地图类型控件
    mapTypeControlOptions: {
        style: google.maps.MapTypeControlStyle.DEFAULT,
		position: google.maps.ControlPosition.TOP_RIGHT
    },
    panControl: true,//平移控件
    panControlOptions: {
        position: google.maps.ControlPosition.RIGHT_CENTER
    },
    zoomControl: true,//缩放控件
    zoomControlOptions: {
        style: google.maps.ZoomControlStyle.DEFAULT,
        position: google.maps.ControlPosition.LEFT_CENTER
    },
	overviewMapControl: true,//鹰眼控件
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    }////////opitions

    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions)/////////////////google map func below this row

	// add marker
	google.maps.event.addListener(map, 'click', function(event) {
	addMarker(event.latLng);//addmarker func,navigation func
	});

	// Create the DIV to hold the control and
	// call the HomeControl() constructor passing
	// in this DIV.
	var homeControlDiv = document.createElement('div');
	var homeControl = new HomeControl(homeControlDiv, map, myLatlng);
	homeControlDiv.index = 1;
	map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv);

	//real time traffic
	var trafficLayer = new google.maps.TrafficLayer();
	trafficLayer.setMap(map);

    geocoder = new google.maps.Geocoder();

    google.maps.event.addListener(map,"center_changed",centerChanged);

    lastrelease = new Date();
    lastcenter = new Date();

    setInterval(function() {
      if ((new Date()).getSeconds() - lastcenter.getSeconds() >1){
          if (lastrelease.getTime() < lastcenter.getTime()) {
              codeLatLng();
          }
      }
    },1000);
  }

  function centerChanged()
  {
      lastcenter = new Date();
      addressresults = null;
  }

  function detectCity(city)
  {
      geocoder.geocode({'address':city},resultPrase);
  }

  function resultPrase(results,status)
  {
      if (status == "OK"){
          if (status != google.maps.GeocoderStatus.ZERO_RESULTS){
		      map.setZoom(15);
              map.setCenter(results[0].geometry.location);
              new google.maps.Marker({map:map,position:results[0].geometry.location})
          }
          else{
             alert("can't find the address");
          }
      }
      else{
        alert("google map error with the reason: "+status);
      }
  }

  function codeLatLng()
  {
      lastrelease = new Date();
      geocoder.geocode({'location':map.getCenter()},resultsLatLng);
  }

  function resultsLatLng(results,status)
  {
      addressresults = results;
      if (status == "OK") {
          if (status !="ZERO_RESULTS") {
			        //from google map v3
              var detail= addressresults[addressresults.length-3].address_components[0].long_name;
			        //from google map v2
			        var fullname = addressresults[0].formatted_address;
      		    if (status == google.maps.GeocoderStatus.OK)
                mapNews.getAddress(fullname,detail);
          }
          else{
              mapNews.findFailed();
          }
      }
      else{
        alert("google map error with the reason: +",status);
      }
   }

	//animation marker style bounce
	function toggleBounce() {
	if (marker.getAnimation() != null) {
	marker.setAnimation(null);
	} else {
	marker.setAnimation(google.maps.Animation.BOUNCE);
	}
	}

	// Add a marker to the map and push to the array.
	function addMarker(location) {//一
	marker = new google.maps.Marker({
	position: location,
	//DROP MODE
	draggable:false,
    animation: google.maps.Animation.DROP,
	map: map
	});
	//creat animation marker style:bounce
	//google.maps.event.addListener(marker, 'click', toggleBounce);
	markers.push(marker);

	//get the latlng ,creat infowindow and display latlng
	geocoder.geocode({ 'location': location }, function (results, status) {
		if (status == google.maps.GeocoderStatus.OK) {
			var lat = results[0].geometry.location.lat();//获得维度
			var lng = results[0].geometry.location.lng();//获得经度
			var add = results[0].formatted_address//获得地址

			var infowindow = new google.maps.InfoWindow({
				content: '<strong>纬度:</strong>' + lat + '<br/><strong>经度:</strong>' + lng + '<br/><strong>地址:</strong>' + add
			});
			//弹出infowindow气泡窗口显示上述信息
			google.maps.event.addListener(marker, 'click', function(){
			infowindow.open(map, marker);
			});
		}
	});

	//if markers >=2 ready for direction
	if (markers.length >= 2) {
		if (markers.length == 2) {
						start = markers[0].getPosition();//路径规划起点
						end = markers[1].getPosition();//路径规划终点
		  }
	if  (markers.length > 2) {
		for(var i=0;i<markers.length;i++)	{
						start = markers[(markers.length)-2].getPosition();
						end = markers[(markers.length)-1].getPosition();
		}}

	//get direcitons route and display
	directionsDisplay.setMap(map);
	var request = {
	origin:start,
	destination:end,
	travelMode: google.maps.DirectionsTravelMode.DRIVING
	};
	directionsService.route(request, function(response, status) {
	if (status == google.maps.DirectionsStatus.OK) {
		directionsDisplay.setDirections(response);
		setTimeout(function() {
		directionsDisplay.setMap(null) }, 10000);//定时清除线路 10s
		}
		});
	}
	}

	// Sets the map on all markers in the array.
	function setAllMap(map) {
	for (var i = 0; i < markers.length; i++) {
	markers[i].setMap(map);
	}}

	// Removes the overlays from the map, but keeps them in the array.
	function clearOverlays() {
	setAllMap(null);
	}

	// Shows any overlays currently in the array.
	function showOverlays() {
	setAllMap(map);
	}

	// Deletes all markers in the array by removing references to them.
	function deleteOverlays() {
	clearOverlays();
	markers = [];
	}

	function addphotolay() {
	// The photoDiv defines the DIV within the info window for
	// displaying the Panoramio photo within its PhotoWidget.
	var photoDiv =  document.createElement('div');

	// The PhotoWidget width and height are expressed as number values,
	// not string values.
	var photoWidgetOptions = {
	width: 320,
	height: 240
	};

	// We construct a PhotoWidget here with a blank (null) request as we
	// don't yet have a photo to populate it.
	var photoWidget = new panoramio.PhotoWidget(photoDiv, null,photoWidgetOptions);

	var infoWindow = new google.maps.InfoWindow();
	var panoramioLayer = new google.maps.panoramio.PanoramioLayer({
	suppressInfoWindows: true
	});

	panoramioLayer.setMap(map);

	google.maps.event.addListener(panoramioLayer, 'click', function(e) {
	var photoRequestOptions = {
	  ids: [{
		'photoId': e.featureDetails.photoId,
		'userId': e.featureDetails.userId
	  }]
	};
	photoWidget.setRequest(photoRequestOptions);
	photoWidget.setPosition(0);
	infoWindow.setPosition(e.latLng);
	infoWindow.open(map);
	infoWindow.setContent(photoDiv);
	});
	}
</script>
</head>
<body style="margin:0px; padding:0px;" onLoad="initialize()">
  <div id="map_canvas" style="width:100%; height:100%"></div>
  	<div id="panel">
	<input onClick="clearOverlays();" type=button value="Hide Overlays">
	<input onClick="showOverlays();" type=button value="Show All Overlays">
	<input onClick="deleteOverlays();" type=button value="Delete Overlays">
	<input onClick="addphotolay();" type=button value="Show Photo">
	<input onclick='parent.location="javascript:location.reload()"' type=button value="Reload" >
	</div>
<div id="crosshair"></div>
</body>
</html>

Written by liby

八月 13th, 2013 at 11:10 上午

Posted in 技事巧事

Tagged with ,