Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   Google Maps en Embarcadero C++ (https://www.clubdelphi.com/foros/showthread.php?t=91925)

lago 04-06-2017 11:46:07

Google Maps en Embarcadero C++
 
Hola, estoy tratando de implementar el soporte de los mapas de Google en mi aplicación. Utilizando la API de Google genero mi HTML desde código para utilizar las funciones basicas de mostrar el mapa y centrarlo utilizando una latitud y una longitud y añadir una imagen de marca de ubicación.

Hasta ahí genial!, el problema viene cuando necesito recoger la latitud y la longitud del mapa al "clickear" en él. En Delphi hay muchos ejemplos que funcionan, pero en C++ se me hace muy complicado traducir dicho código...

Encuentro estos dos ejemplos en Delphi donde muestra la manera de hacerlo:
https://theroadtodelphi.com/2011/06/...a-mouse-click/
http://delphidabbler.com/tips/56

Aquí esta la función de la "chicha" que me tiene loco...

Código:

procedure TFrmMain.WebBrowser1CommandStateChange(ASender: TObject;  Command: Integer; Enable: WordBool);
var
  ADocument : IHTMLDocument2;
  ABody    : IHTMLElement2;
  Lat : string;
  Lng : string;
 
      function GetIdValue(const Id : string):string;
      var
        Tag      : IHTMLElement;
        TagsList : IHTMLElementCollection;
        Index    : Integer;
      begin
        Result:='';
        TagsList := ABody.getElementsByTagName('input');
        for Index := 0 to TagsList.length-1 do
        begin
          Tag:=TagsList.item(Index, EmptyParam) As IHTMLElement;
          if CompareText(Tag.id,Id)=0 then
            Result := Tag.getAttribute('value', 0);
        end;
      end;
 
begin
  if TOleEnum(Command) <> CSC_UPDATECOMMANDS then
    Exit;
 
  ADocument := WebBrowser1.Document as IHTMLDocument2;
  if not Assigned(ADocument) then
    Exit;
 
  if not Supports(ADocument.body, IHTMLElement2, ABody) then
    exit;
 
  Lat :=GetIdValue('LatValue');
  Lng :=GetIdValue('LngValue');
  if  (Lat<>'') and (Lng<>'') and ((Lat<>Latitude.Text) or (Lng<>Longitude.Text)) then
  begin
    Latitude.Text :=Lat;
    Longitude.Text:=Lng;
    AddLatLngToList(Lat, Lng);
  end;
end;

O bien:

Código:

function GetElementById(const Doc: IDispatch; const Id: string): IDispatch;
var
  Document: IHTMLDocument2;    // IHTMLDocument2 interface of Doc
  Body: IHTMLElement2;          // document body element
  Tags: IHTMLElementCollection; // all tags in document body
  Tag: IHTMLElement;            // a tag in document body
  I: Integer;                  // loops thru tags in document body
begin
  Result := nil;
  // Check for valid document: require IHTMLDocument2 interface to it
  if not Supports(Doc, IHTMLDocument2, Document) then
    raise Exception.Create('Invalid HTML document');
  // Check for valid body element: require IHTMLElement2 interface to it
  if not Supports(Document.body, IHTMLElement2, Body) then
    raise Exception.Create('Can''t find <body> element');
  // Get all tags in body element ('*' => any tag name)
  Tags := Body.getElementsByTagName('*');
  // Scan through all tags in body
  for I := 0 to Pred(Tags.length) do
  begin
    // Get reference to a tag
    Tag := Tags.item(I, EmptyParam) as IHTMLElement;
    // Check tag's id and return it if id matches
    if AnsiSameText(Tag.id, Id) then
    begin
      Result := Tag;
      Break;
    end;
  end;
end;


Se trata de recoger el contenido en un TWebBrowser (en este caso un mapa de google maps cargado desde un .html que creo desde mi programa) para mostrar lo almacenado en
Código:

  <input type="hidden" id="LatValue" >
  <input type="hidden" id="LngValue" >

Llevo varios días buscando pero no consigo encontrar nada que me aclare como hacerlo. He encontrado un proyecto chulo, las GMLib pero como solo necesito poder recoger la latitud y longitud en un click no quisiera añadirlas a mi proyecto.

Alquien podría indicarme como sería esa función en C? O bien donde encontrar más documentación? He terminado leyendo post en alemán y en ruso pero no consigo aclararme ! :)

Muchas gracias por vuestro tiempo, y un saludo!

Jorge.

_Leo 05-06-2017 03:31:48

Hola, prueba del siguiente modo:

(Añade las siguientes cabeceras: #include<utilcls.h> #include<mshtml.h>)

Código:

void __fastcall TFrmMain::WebBrowser1CommandStateChange(TObject *ASender,
        int Command, WordBool Enable)
{
    if (Command != ::CSC_UPDATECOMMANDS) return;

    String Lat, Lng;
    TComInterface<IHTMLDocument3> doc;
    TComInterface<IHTMLElement> tag;
    TVariant value;

    OleCheck(WebBrowser1->Document->QueryInterface<IHTMLDocument3>(&doc));
    doc->getElementById(TVariant("LatValue"), &tag);
    if (tag) { tag->getAttribute(TVariant("value"), 0, value);  Lat = value; }
    tag.Reset();
    doc->getElementById(TVariant("LngValue"), &tag);
    if (tag) { tag->getAttribute(TVariant("value"), 0, value);  Lng = value; }

    if (!Lat.IsEmpty() && !Lng.IsEmpty()
        && (Lat != Latitude->Text || Lng != Longitude->Text))
    {
        Latitude->Text = Lat;
        Longitude->Text = Lng;
        AddLatLngToList(Lat, Lng);
    }
}


lago 05-06-2017 11:21:34

Hola Leo! Muchísimas gracias! ahora funciona!

Por si le sirve de algo a alquien:

Al cargar el mapa me he encontrado con un error de javascript, más en concreto onion.js. Leyendo me he encontrado que dicha librería utiliza funciones de JSON. Bastaría con añadir

Código:

<script src="https://cdn.jsdelivr.net/json3/3.3.2/json3.js"></script>
A HTML que generamos y funciona... completo:

Código:

<html>
<head>               
<meta name="viewport" content="initial-scale=1.0, user-scalable=yes" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>

<script src="https://cdn.jsdelivr.net/json3/3.3.2/json3.js"></script>

<script type="text/javascript">
  var geocoder;
  var map; 
  var markersArray = [];

  function initialize() {
    geocoder = new google.maps.Geocoder();
    var latlng = new google.maps.LatLng(40.714776,-74.019213);
    var myOptions = {
      zoom: 13,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
    map.set("streetViewControl", false);
    google.maps.event.addListener(map, "click",
        function(event)
                        {
                        document.getElementById("LatValue").value = event.latLng.lat();
                        document.getElementById("LngValue").value = event.latLng.lng();
                        PutMarker(document.getElementById("LatValue").value, document.getElementById("LngValue").value,"")
                        }
  );

  }

  function GotoLatLng(Lat, Lang) {
  var latlng = new google.maps.LatLng(Lat,Lang);
  map.setCenter(latlng);
  }


function ClearMarkers() { 
  if (markersArray) {       
    for (i in markersArray) { 
      markersArray[i].setMap(null);
    }
  }


  function PutMarker(Lat, Lang, Msg) {
  var latlng = new google.maps.LatLng(Lat,Lang);
  var marker = new google.maps.Marker({
      position: latlng,
      map: map,
      title: Msg+" ("+Lat+","+Lang+")"
  });
  markersArray.push(marker);
  index= (markersArray.length % 10);
  if (index==0) { index=10 }
  icon = "http://www.google.com/mapfiles/kml/paddle/"+index+"-lv.png";
  marker.setIcon(icon);
  }

</script>
</head>

<body onload="initialize()">
  <div id="map_canvas" style="width:100%; height:100%"></div>
  <div id="latlong">
  <input type="hidden" id="LatValue" >
  <input type="hidden" id="LngValue" >
  </div> 

</body>
</html>

Muchas gracias!

lago 05-06-2017 11:57:11

Completo con lo que faltaba que es poder ejecutar funciones JavaScript y que he encontado por ahi y rula

Código:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 IHTMLDocument2  *doc = NULL;
  IHTMLWindow2 *win;
  if(SUCCEEDED(WebBrowser1->Document->QueryInterface(IID_IHTMLDocument2, (LPVOID*)&doc)))  {
        HRESULT hr = doc->get_parentWindow(&win);
        if (SUCCEEDED(hr))  {
          BSTR cmd = L"ClearMarkers()";
          VARIANT v;
          VariantInit(&v);
          win->execScript(cmd,NULL,&v);
          VariantClear(&v);
          win->Release();
        }
        doc->Release();
  }

Y función con parametros:

Código:

void __fastcall TForm1::Button2Click(TObject *Sender)
{
  IHTMLDocument2  *doc = NULL;
  IHTMLWindow2 *win;
  if(SUCCEEDED(WebBrowser1->Document->QueryInterface(IID_IHTMLDocument2, (LPVOID*)&doc)))  {
        HRESULT hr = doc->get_parentWindow(&win);
        if (SUCCEEDED(hr))  {
          String str = String("GotoLatLng(") + Edit1->Text + "," + Edit2->Text + ")";
          VARIANT v;
          VariantInit(&v);
          win->execScript( str.w_str(), NULL, &v );
          VariantClear  ( &v );
          win->Release  ();
        }
        doc->Release();
  }
}


_Leo 05-06-2017 15:36:02

Cita:

Empezado por lago (Mensaje 517673)
Al cargar el mapa me he encontrado con un error de javascript, más en concreto onion.js. Leyendo me he encontrado que dicha librería utiliza funciones de JSON...

Yo lo he dejado tal cual como estaba en el código original, lo que si he tenido es que añadir en la siguiente rama del registro:

Código:

HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION
El siguiente valor:

Código:

SustituirPorElNombreDeTuEjecutable.exe (REG_DWORD) 11001 (valor decimal)
Para así forzar que use el motor de Internet Explorer 11, en lugar del 7 que usa ese control por defecto. También he puesto la propiedad “Silent” a true. Sin el primer cambio daba errores constantes de JavaScript, y solo con el segundo hacia que funcionase a veces y solo por un rato.

lago 05-06-2017 19:58:44

Algo había leído al respecto... hace un rato buscando he encontrado esto:

https://msdn.microsoft.com/es-es/library/cc817574.aspx

Maneras de activar los modos de compatibilidad.

Estoy utilizando esto:
Código:

<meta http-equiv="X-UA-Compatible" content="IE=edge" />
Forzando al uso del Edge. A ver si después arranco el VMWare y pruebo con un Windows 7 y su explorer...

_Leo 05-06-2017 21:32:08

Cita:

Empezado por lago (Mensaje 517724)

Estoy utilizando esto:
Código:

<meta http-equiv="X-UA-Compatible" content="IE=edge" />
Forzando al uso del Edge. A ver si después arranco el VMWare y pruebo con un Windows 7 y su explorer...

Fue lo primero que probé, pero lo ignora totalmente, al menos en Windows10.


La franja horaria es GMT +2. Ahora son las 14:43:27.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi