Google Maps en Delphi – II
En la última entrada acerca de la API de Google Maps, vimos cómo mostrar un Mapa utilizando la API en un programa Delphi, cómo centrarlo en una posición predefinida y utilizando un Zoom predeterminado.
Además como seleccionar entre los diferentes controles que podemos añadir al mapa (Zoom, Vista general, tipo de mapa…).
También cómo colocar una marca en una ubicación y cómo generar una ventana con información asociada a esa marca (NOTA1).
NOTA1: De forma similar se pueden colocar otros elementos sobre el mapa, como:
- Líneas, polilíneas y polígonos.
- Marcas con iconos personalizados.
- Rutas
- …
Una vez visto cómo mostrar el mapa, lo que nos queda es ver cómo podemos, desde nuestro programa Delphi, interactuar con él; Es decir, que el usuario pueda modificar determinadas características del mapa que tiene en pantalla, y nosotros podamos recuperar esos cambios, para utilizarlos en nuestro programa.
Vamos a continuar con el ejemplo visto en las entradas anteriores; Mostraremos al usuario un Mapa ubicado en una determinada posición. El usuario debe poder «reubicar» la vista del mapa y modificar el Zoom con que está visualizando el mapa, y esos son los valores que obtendremos para posteriormente almacenarlos y actualizarlos en nuestro programa.
- Coordenada de Longitud
- Coordenada de Latitud
- Zoom actual del mapa
La forma de conseguirlo, es añadir a la página web el código necesario para capturar eventos que se produzcan en el mapa. Incluiremos controles de edición, donde se almacenan la longitud/latuitud y Zoom, que después recuperaremos desde el programa Delphi.
GEvent.addListener(map, "click", function (overlay,point) GEvent.addListener(map, "zoomend", function (oldLevel, newLevel) GEvent.addListener(map, "mousemove", function(latlng) |
Aunque uno no esté muy familiarizado con el tema (yo mismo no lo estoy mucho ;-D ), no hacen falta muchas explicaciones para comprender los eventos; «Capturaremos» en OnClick, OnZoomEnd y OnMouseMove sobre el mapa. Aquí se puede acceder a la lista de eventos, métodos y propiedades de la clase Gmap.
En el caso del evento OnClick, por ejemplo, utilizaremos un código como este:
GEvent.addListener(map, "click", function (overlay,point){ if (point){ document.posicion.x.value=point.x document.posicion.y.value=point.y document.posicion.z.value=map.getZoom() TipoMapa = map.getCurrentMapType().getName() document.posicion.t.value=TipoMapa } |
Obtenemos información del punto actual (utilizando un parámetro) y el Zoom actual y el tipo de Mapa utilizando métodos de la clase GMap. Todos ellos se almacenan (como hemos comentado antes) en componentes de tipo Text, que nos sirven como «paso intermedio» para luego capturar esos valores de la página Web desde nuestro programa.
Como resultado final, os dejo el ejemplo que se adjunta con esta entrada. En él he incluído/integrado la parte de Geocodificación (visto en las entradas I y II), y el código y modificaciones necesarias para recuperar posición, Zoom y tipo de Mapa (este incluído a última hora) que el usuario selecciona en un Mapa.
La información de los lugares puede ser guardada y recuperada de un fichero de texto; La estructura es bastante simple y no hace falta mayor explicación. Se almacena en el mismo directorio de la aplicación y recibe el nombre de «Lugares.txt».
La información que podemos capturar del Mapa (utilizando la clase GMap) y de otros elementos que estén incluíds en el mapa (imágenes, líneas, marcas,…) es muy extensa y está detallada en las referencias de la API de Google Maps.
Personalmente, creo que las posibilidades de ampliación son muy grandes y bastantes más sencillas de lo que a priori puede parecer.
Se puede descargar el ejemplo completo desde aquí.
<DESCARGAR EJEMPLO>
Espero que estas entradas hayan sido de utilidad. Como siempre cualquier comentario, corrección, sugerencia,… es bienvenida. ;-D
Un saludo.
ACTUALIZACIÓN (10 Febrero 2012): Dado el cambio de política de Google, ahora es necesario (obligatorio) colocar la key que se proporciona desde Google para poder utilizar la API. Es necesario modificar el fichero _mapa.txt del recurso y recompilarlo utilizando RC.CMD.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Buen final a esta serie de entradas. Hay detalles que desconocía y que me van a ser muy útiles.
Gracias.
Me entro la curiosidad de meter esta herramienta a mi aplicación para buscar mapas, todo va bien hasta el momento de pulsar el boton buscar me salta el siguiente error:
ERROR NO SE ENCUENTRA EL RECURSO
Precisamente marca error en el siguiente codigo:
// Se trata de seguridad de Visualizacion?
resName := RES_HTML_PAGEMAP;
// Llamar a la búsqueda de recurso
b := FindInstanceOfResource(resName, RT_RCDATA, HInstance);
// NO ENCUENTRA EL RECURSO Y MARCA EL ERROR
if not b then begin
// Error de recurso no encontrado
raise Exception.Create(EMAP_MSG_ERRORGETRES);
Application.Terminate;
end;
Agradezco tus comentarios….
Me falto informarte que ya copie el archivo MapaRES.res en la ruta donde se encuentra el .pas y en diferentes rutas haber si eso es el problema pero no doy :)….
@Alfredo Angulo
Hola Alfredo.
Acabo de actualizar el link del ejemplo. Prueba a compilarlo ahora y a ejecutarlo.
http://neftali.clubdelphi.com/ejemplos_files/Ej1_googlemaps.zip
@Alfredo Angulo
Te acabo de subir una versión «extraoficial» que carga la página desde el fichero TXT directamente, por si sigue sin funcionarte.
http://neftali.clubdelphi.com/ejemplos_files/Ej1_googlemaps_bis.zip
Un saludo.
Gracias por tus respuestas, pero haz la prueba con un nuevo proyecto, agregas un boton y alli mandas llamar el formulario FVerMapa.pas de la siguiente forma :
[DELPHI]
try
Application.CreateForm(tFormVerMapa,FormVerMapa);
FormVerMapa.ShowModal;
finally
FormVerMapa.Free;
end;
[/DELPHI]
Corres el programa, presionas el boton y te saldrá el formulario par buscar un lugar, le escribes algun lugar y presionas enter y te marca el error de que no se encuentra el recurso, lo que trato de decir es que el ejemplo no funciona cuando es llamada de otro proyecto, si yo lo corro asi como viene el ejemplo después de descomprimir el archivo que subistes ese no marca error todo jala muy bien, pero si intentas añadirlo a un formulario de algun programa no funciona…. me explico ???
Añadi el recurso .rc, y se me agrego en el .dpr ( proyecto ) una linea nueva:
{$R ‘..\..\Utilerias\GoogleMaps\MapaRes.res’ ‘..\..\Utilerias\GoogleMaps\MapaRes.rc’}
Al compilar me marca ahora el sigu
siguiente error de compilación:
[Error] Warning . Duplicate Resource(s)
Disculpa Neftalli por tanto mensaje, lo que pasa es que es la 1er vez que añado un archivo .res al proyecto, ya logre que funcionará, quite la linea donde toma todos los archivos de recursos y puse el nuevo, por eso marcaba error:
//{$R *.res}
{$R ‘..\..\Utilerias\GoogleMaps\MapaRes.res’ ‘..\..\Utilerias\GoogleMaps\MapaRes.rc’}
Gracias que tengas buen día, y te reconozco que te quedo muy bien tu aplicacion de google maps, muy bueno, solo una ultima pregunta, como se puede dejar por default la opción del mapa HIBRIDO ???? ya vez que cuando buscar un lugar te sale el mapa y en la parte superior derecha hay 3 opciones: 1.- MAPA 2.- SATELITE 3.- HIBRIDO, sale por default MAPA….
@Alfredo Angulo
Hay un procedimiento llamado:
procedure _ChangeMapType();
Que es donde se configura el tipo de mapa;
Se busca la línea:
STR_PREFIX_TYPE = ‘##MAPTYPE##’;
Y se sustituye por esta otra configurada segun el tipo de mapa:
STR_TYPE = ‘ map.setMapType(%s);’;
Si cambias ese procedimiento por este, aparecerá siempre el mapa híbrido:
//············································································
procedure _ChangeMapType();
const
STR_PREFIX_TYPE = ‘##MAPTYPE##’;
STR_TYPE = ‘ map.setMapType(%s);’;
var
i, j:Integer;
str, line:string;
begin
// Buscar la cadena
for i := 0 to (TSWeb.Count – 1) do begin
line := Self.TSWeb[i];
j := AnsiPos(STR_PREFIX_TYPE, line);
// Es la línea
if (j > 0) then begin
Str := Format(STR_TYPE,[G_HYBRID_MAP]);
Self.TSWeb[i] := Str;
Self.TSWeb.SaveToFile(Self.FNameWeb);
Break;
end;
end;
end;
//············································································
Gracias, neftalli, te quedo muy bien, hay lugares que no salen los nombres de las calles, es porque en google todavia no las actualiza ????
por darte un ejemplo MORELIA, MICHOACAN acercas el mapa y no salen los nombres de las calles solo las carreteras, y si buscas GUADALAJARA, JALISCO si te salen las calles si lo acercas….
Ultima pregunta Neftalli, entre a esta pagina http://maps.google.es/ y si busco alli por ejemplo MORELIA, MICHOACAN salen 4 opciones en la parte superior derecha la primera es para agregar fotos que caracterizan al lugar, la 4ta se llama RELIEVE, alli si lo presiono empiezan a salir los NOMBRES de las calles del lugar, veo que estas usando la misma dirección http://maps.google.es/maps?&q=%s,%s&z=15 pero no entiendo porque no aparece lo mismo en la aplicación de delphi que en la pagina de maps.google ??
otra cosa, lo que pasa es que pienso meter esta herramienta en 2 aplicaciones y dichas aplicaciones usan diferentes imagenes de icono en el .exe y me los cambia, si es algo molesto estar cambiando el nombre del icono para que tome el que le corresponde, porque mejor que habilite el boton «LOAD ICON» del Menu Project-Options-Aplication, estoy buscando donde le da la orden de que se deshabilite ese boton :)
@Alfredo Angulo
Lo de las calles es normal. No todas las ciudades tienen igual de actualizados mapa e imágenes.
@Alfredo Angulo
Si encuentra un fichero de recurso con un icono llamado MAINICON, creo que por defecto toma este en lugar de el configurado en las opciones del proyecto.
Un saludo.
@Alfredo Angulo
En esa dirección que comentas (http://maps.google.es/maps?&q=%s,%s&z=15) lo que hace la aplicación es sustituir los %s por las coordenadas de longitud y Latitud.
Como defines los botones que aparecen arriba a la derecha, si entro al http://maps.google.com/ y busco LOS MOCHIS, SINALOA alli si muestra los nombres de las calles presionando el boton RELIEVE ..
@Alfredo Angulo
Para el tipo de Mapa RELIEVE puedes utilizar como constante de Tipo de mapa: G_PHYSICAL_MAP
Para obtener más información puedes mirar la API de Google Maps y hacer pruebas modificando el fichero de recurso.
Donde aparece esta línea:
map.addControl(new GLargeMapControl());
Añade debajo estas dos.
map.addMapType(G_PHYSICAL_MAP);
map.setMapType(G_PHYSICAL_MAP);
gracias neftalli, ya le agarre el rollo a esto…. :)
Fantástico trabajo! Muchas gracias por dedicar tu tiempo a compartir estos recursos :)
Muchas gracias por el ejemplo, gran trabajo.
Deseo poder colocar otros objetos (polilineas) sobre los mapas, pero no se por donde empezar, puedes explicarme que debo hacer para trazar una sola linea, ya lei el tutor de la API de Google, pero no tengo idea en que parte de delphi debo encajar el codigo, por ejemplo.
var polyline = new GPolyline([
new GLatLng(37.4419, -122.1419),
new GLatLng(37.4519, -122.1519)
], «#ff0000», 10);
map.addOverlay(polyline);
Muchas gracias
Estoy trabajando todavía con Delphi 5, sabríais decirme si las Indy para esta versión funcionan con este ejemplo?.
Y por cierto, no encuentro las Indy para esta versión de Delphi. Podríais decirme de donde bajarlas.
Gracias.
@Marco
Hola Marco.
Revisa el código de la página Web que se usa en el ejemplo y añade en la página el código para la poliliea.
Lo más sencillo es que primero lo pruebes con una página web estática y luego lo integres en el ejemplo.
Un saludo.
@socger
Hola socger.
La verdad es que no lo he probado con Delphi 5.
Puedes descargar el último paquete de las indy desde aquí:
http://www.indyproject.org/Sockets/Download/Files/Indy10.DE.aspx
Gracias, he conseguido instalar las Indy 10 en Delphi 5, pero ahora al abrir tu código me doy cuenta que no tenemos la misma versión de Delphi (cosa lógica). ¿Te importaría decirme que versión es con la que trabajas para probar tus ejemplos?.
Esto lo necesito porque por ejemplo el ejemplo 2 de geoCodificacion no lo puedo ni abrir. El primero lo pude abrir y modificar para que funcionara en Delphi 5
Mi cuenta de correo es socger@hotmail.com por si podrías decirme esto por correo privado.
Saludos y gracias de antemano.
@Germán Estévez
Logre hacer las polilineas, y la integracion con los ejemplos de Google, gracias a tus instrucciones y ejemplos (no estaba leyendo los casos anteriores) MUCHAS GRACIAS.
Hello Nefali.
Great work !
But , is there a way to get the coordinates of a marker – from google maps, back to delphi ?
Hello. Something is changed on Google.
This error is describes here.
I’am reading for a solution.
=============================
Hola.
Parece que algo ha cambiado recientemente en cómo Google responde las peticoines (relacionado con la API).
Este post parece que explica el problema.
Ok.
Parece que basta con obtener una API Key aquí:
http://code.google.com/intl/es-ES/apis/maps/signup.html
Y añadir a la llamada el parámetro con la Key obtenida.
Por ejemplo:
&key=AWEAGB98698….. (vuestra key)
Un saludo.
SOLUCIÓN: Utilizando una API key válida todo funciona correctamente.
He subido los ejemplos actualizados.
Un saludo.
Felicitaciones, muy bien explicado y muy práctico.
Voy a utilizarlo dentro de mi aplicación.
Saludos.
Buenas Tardes Neftali disculpa en el codigo ya modifique el parametro &hey y me sigue marcando el error que no poporciona el codigo
esto Tengo en mi codigo
const
STR_WEB = ‘http://maps.google.com/maps/geo?q=’;
STR_KEY = ‘&key=ABQIAAAAFVb255bTSpn4DC0nkcIz3hTgmueMIh62ahlPS2dC-DIXqzciAxRZItsH3Fy4UcBpz0Q4D8XHzbxt3A’;
Y cuando hace el Html pone esto
@Carlos Rocha
Hola Carlos.
La key de Google debes colocarla en el HTML. HE subido el ejemplo actualizado.
Fíjate que hay un fichero de recursos (_mapa.txt) que tiene el código necesario para añadir la key. En ese lugar es donde se debe añadir la key que proporciona Google.
Una vez actualizado el recurso, generamos el fichero .RES compilado (para ello utiliza RC.CMD).
Con el fichero de recursos regenerado correctamente (MAPA.RES), vuelve a recompilar el proyecto y a ver qué tal.
Un saludo.
SON UNOS EJEMPLOS GRANDIOSOS SR. NEFTALI
ME HAN AYUDADO DEMACIADO AL IR COMPRENDIENDO
DELPHI
Hola Neftali.
Estoy probando los ejemplos de mapas, para implementar en un sistema de logistica.
Uso la version 10.3.3 de Delphi. Y al intentar ejecutar el ejemplo me sale este error.
[dcc32 Error] FVerMapa.pas(210): E2250 There is no overloaded version of ‘EnumResourceModules’ that can be called with these arguments
@Francisco
Hola Francisco.
Perdona que no haya contestado antes, pero a veces se me van los comentarios al SPAM y tardo en verlos.
Para que compile, bastaría que cambies el parámetro de la función _MyEnumResourceModules, de un Longint a un HINST.
Con eso debería bastar.
Otra cosa es que posiblemente no llegue a mostrarse, porque han cambiado la APIs de Google. Deberás revisarlas y mirar el tema de la APIKEY.