16 03 2016
Lendo coordenadas GPS no Windows Forms
Com a mobilidade cada vez mais em alta nos dias de hoje, não é raro termos que determinar a posição em que o usuário está localizado. A empresa onde eu trabalho atualmente, por exemplo, desenvolveu um sistema de coleta de dados onde o usuário indica os atributos de pilhas de madeira no meio da floresta. Nesse caso, a posição da pilha de madeira é muito importante, uma vez que a empresa contratada para fazer o transporte da madeira deve saber a localização exata das pilhas.
A Microsoft disponibiliza diretamente no .NET Framework uma biblioteca que possibilita a leitura da posição do usuário utilizando o sistema de localização do Windows. No artigo de hoje veremos como utilizar as classes dessa biblioteca para lermos coordenadas GPS no Windows Forms.
Construindo o formulário de exemplo
Para estudarmos a questão de coordenadas GPS com o .NET Framework, vamos criar um novo projeto do tipo “Windows Forms Application“. Nesse projeto, vamos ajustar o formulário criado automaticamente pelo Visual Studio, adicionando dois Labels, dois TextBoxes (latitudeTextBox e longitudeTextBox) e um Button (lerCoordenadasButton). A ideia é que, ao clicarmos no botão “Ler Coordenadas“, nós preencheremos os TextBoxes com as coordenadas disponibilizadas pela biblioteca. O formulário deve ficar parecido com a imagem abaixo:
Por padrão, configure a propriedade “Enabled” do botão “Ler Coordenadas” como “false“. Nós habilitaremos o botão somente quando o sistema de geoposicionamento estiver ativado e pronto para uso.
A classe GeoCoordinateWatcher
A classe responsável pela leitura de coordenadas GPS no .NET Framework é a GeoCoordinateWatcher. Essa classe é disponibilizada em um assembly separado, ou seja, nós precisamos adicionar uma referência extra (System.Device) caso queiramos utilizá-la no nosso projeto.
Para adicionarmos a referência ao assembly System.Device, temos que ir até a tela de referências do nosso projeto para marcarmos a opção na categoria “Framework“:
Feito isso, vamos declarar uma nova instância da classe GeoCoordinateWatcher dentro do nosso formulário:
public partial class FormGPS : Form { private System.Device.Location.GeoCoordinateWatcher _geoCoordinateWatcher = new System.Device.Location.GeoCoordinateWatcher(); public FormGPS() { InitializeComponent(); } }
Como mencionei anteriormente, nós temos que habilitar o botão “Ler Coordenadas” somente quando o sistema de geoposicionamento estiver pronto para uso. E como é que conseguimos detectar se o sistema está pronto? Simples: através do evento StatusChanged. Esse evento é disparado sempre que o status do sistema de localização do Windows é alterado. Dessa forma, conseguimos verificar se o status está “Pronto para uso” e, caso positivo, nós habilitaremos o botão:
public FormGPS() { InitializeComponent(); _geoCoordinateWatcher.StatusChanged += GeoCoordinateWatcher_StatusChanged; _geoCoordinateWatcher.Start(); } void GeoCoordinateWatcher_StatusChanged(object sender, System.Device.Location.GeoPositionStatusChangedEventArgs e) { lerCoordenadasButton.Enabled = e.Status == System.Device.Location.GeoPositionStatus.Ready; }
Note que logo depois da configuração do hook para o evento, nós chamamos o método Start. Como o próprio nome diz, esse método inicializará o sistema de posicionamento do Windows. Uma vez que o sistema estiver pronto, o evento StatusChanged será disparado e o nosso botão “Ler Coordenadas” será habilitado.
Será que funciona? Vamos testar?
Ao executarmos a aplicação, recebemos este erro:
Cross-thread operation not valid: Control ‘lerCoordenadasButton’ accessed from a thread other than the thread it was created on.
Esse erro acontece porque o mecanismo de geoposicionamento é executado em uma thread separada (e não na thread de UI). Dessa forma, não podemos simplesmente alterar propriedades de controle de dentro desse evento. Para alterarmos propriedades de controles, temos que utilizar o método Invoke:
void GeoCoordinateWatcher_StatusChanged(object sender, System.Device.Location.GeoPositionStatusChangedEventArgs e) { if (lerCoordenadasButton.InvokeRequired) lerCoordenadasButton.Invoke(new Action(() => lerCoordenadasButton.Enabled = e.Status == System.Device.Location.GeoPositionStatus.Ready)); else lerCoordenadasButton.Enabled = e.Status == System.Device.Location.GeoPositionStatus.Ready; }
Execute a aplicação novamente e veja que agora o botão “Ler Coordenadas” será habilitado assim que o mecanismo de geoposicionamento estiver pronto.
Agora que já temos o GeoCoordinateWatcher inicializado e pronto para ler coordenadas, vamos ver como ficaria o código do clique do botão “Ler Coordenadas“:
private void lerCoordenadasButton_Click(object sender, EventArgs e) { if (_geoCoordinateWatcher.Status == System.Device.Location.GeoPositionStatus.Ready) { latitudeTextBox.Text = _geoCoordinateWatcher.Position.Location.Latitude.ToString(); longitudeTextBox.Text = _geoCoordinateWatcher.Position.Location.Longitude.ToString(); } }
Veja que o código é extremamente simples. Antes de tentarmos acessar a posição, para evitarmos problemas, nós asseguramos mais uma vez que o Status do GeoCoordinateWatcher está realmente “Ready“. Uma vez feita essa confirmação, nós simplesmente acessamos as informações de latitude e longitude através das propriedades Position.Location.Latitude e Position.Location.Longitude.
E este é o resultado:
Definindo a precisão desejada
Quão precisas são as coordenadas retornadas pelo GeoCoordinateWatcher? Por padrão, o sistema de geoposicionamento do Windows retornará as coordenadas mais precisas possíveis, utilizando a menor quantidade de energia possível. Ou seja, em um laptop sem GPS, provavelmente o Windows retornará a posição através do seu IP, roteador WiFi ou antenas de celular. Em um dispositivo com GPS, o Windows provavelmente utilizará o próprio GPS, caso o nível de bateria do dispositivo não esteja muito baixo.
Uma das propriedades de “Location” é a precisão (em metros). No meu caso, a precisão da coordenada retornada foi de 130 metros:
No caso da sua aplicação ser instalada em um dispositivo com GPS, muitas vezes você pode querer que a coordenada retornada seja a mais precisa possível (ou seja, sempre utilizando o dispositivo GPS). A classe GeoCoordinateWatcher possui uma propriedade DesiredAccuracy, porém, o que acontece ao tentarmos alterá-la?
_geoCoordinateWatcher.DesiredAccuracy = System.Device.Location.GeoPositionAccuracy.High;
Como é que podemos alterar a DesiredAccuracy se a propriedade é somente leitura? Simples: temos que especificar a precisão desejada no construtor do GeoCoordinateWatcher:
private System.Device.Location.GeoCoordinateWatcher _geoCoordinateWatcher = new System.Device.Location.GeoCoordinateWatcher(System.Device.Location.GeoPositionAccuracy.High);
Nota: somente altere a precisão desejada para “High” caso você realmente precise de coordenadas com alta precisão. De acordo com a documentação, essa alteração pode causar degradação na performance e um aumento significativo no consumo de bateria.
Outras propriedades da localização
Além das propriedades de latitude, longitude e precisão, temos algumas outras propriedades disponíveis:
Em especial, gostaria de destacar as seguintes propriedades:
– Altitude: a altitude, em metros, em relação ao nível do mar. Esse valor só será retornado caso a coordenada tenha sido capturada com um dispositivo de alta precisão (GPS, por exemplo)
– Course: a direção, em graus relativos ao norte, em que o usuário está se movimentando. Com essa informação, podemos calcular, por exemplo, se o usuário está se movimentando para o norte, sul, leste ou oeste
– Speed: a velocidade, em metros por segundo, em que o usuário está se movimentando. Propriedade muito interessante para aplicativos de navegação
Concluindo
Capturar a posição onde o usuário está localizado é muito simples em aplicações desenvolvidas com o .NET Framework. A classe GeoCoordinateWatcher possui todas as informações relacionadas à posição do usuário, informações estas que são obtidas através do próprio sistema de geoposicionamento do Windows.
Neste artigo você conferiu como capturar as coordenadas atuais do dispositivo, como alterar a precisão em que as coordenadas são capturadas e, por fim, algumas outras propriedades interessantes que você pode utilizar ao trabalhar com geoposicionamento (como altitude, direção e velocidade).
Você consegue identificar alguma das suas aplicações que poderia se beneficiar dessa funcionalidade? Conte-nos mais detalhes nos comentários logo abaixo!
Antes de me despedir, convido você a inscrever-se na minha newsletter. Ao fazer isso, você receberá um e-mail toda semana sobre o artigo publicado, ficará sabendo em primeira mão sobre o artigo da próxima semana e receberá também dicas “bônus” que eu só compartilho por e-mail. Além disso, você já deve ter percebido que eu recebo muitas sugestões de temas e eu costumo dar prioridade às sugestões vindas de inscritos da minha newsletter. Inscreva-se utilizando o formulário logo abaixo.
Até a próxima!
André Lima
Photo by Pixabay used under Creative Commons
https://pixabay.com/en/compass-north-compass-point-356769/
Passando parâmetros para relatórios do Crystal Reports com C# Mandando uma DataTable filtrada para o Report Viewer
Muito bom mesmo, muito obrigado André pela dica Deus te abençoe sempre
Você poderia publicar também em vb ?
Olá Jorge, muito obrigado pelo comentário!
Não tenho o exemplo pronto em VB.NET, mas, existem vários conversores online de C# para VB.NET.. Dê uma olhada neste, por exemplo:
Telerik Code Converter
Se você tiver algum problema na conversão, me avisa que eu te ajudo..
Abraço!
André Lima
Boa tarde
Muito bom o conteúdo e realmente consegui aplicar, somente não consegui utilizar o Accuracy… Mesmo declarando toda a informação ele ainda continua com o mesmo erro, falando que é somente leitura.
Olá Lucas, obrigado pelo comentário!
Você tentou passar a Accuracy no construtor do GeocoordinateWatcher e recebeu um erro que ela é read-only? Qual foi exatamente o código que você utilizou?
Abraço!
André Lima
Eu consigo usando GeoCoordinateWatcher jogar duas coordenadas já existente e ele me dar os metros entre elas?
Olá Ewerton!
Você não precisa do GeoCoordinateWatcher para fazer isso.. Basta a classe GeoCoordinate (sem Watcher no final).. Ela tem um método “GetDistanceTo” que faz esse tipo de cálculo.. Veja um exemplo na documentação do MSDN:
GeoCoordinate.GetDistanceTo Method
Abraço!
André Lima