domingo, 22 de maio de 2016

Criando um Navegador Web com TWebBrowser

Na paleta Internet, há um componente chamado WebBrowser (da classe TWebBrowser), o qual podemos usar para construir um pequeno - porém eficiente - navegador Web. Coloque um WebBrowser no seu formulário e adicione também uma Toolbar (paleta Win32), que servirá de barra de ferramentas. Na Toolbar, use o botão direito do mouse para colocar os botões de Voltar, Avançar e Página Inicial ("Home"). 
Clique em cada botão criado e modifique a propriedade Name de cada um para BtVoltar, BtPaginaInicial e BtAvancar, respectivamente (note que não se usa  "ç" em nomes de componentes e objetos).
Você também pode aumentar o tamanho dos botões da Toolbar para que eles possam abrigar figuras maiores. Basta clicar na Toolbar e, nas propriedades ButtonHeight e ButtonWidth, alterar os valores para 32, indicando que os botões terão, agora, altura e largura iguais a 32 pixels.
Coloque, ainda, um componente Edit (paleta Standard) na Toolbar para servir de barra de endereços. Assim, podemos usá-lo para digitar os endereços web. Inclua, ainda, uma StatusBar (paleta Win32), que será nossa barra de status. Ela ficará posicionada, automaticamente, no rodapé do formulário. Após estas modificações e de ajustar os componentes adequadamente na tela, a aparência de seu aplicativo deverá estar semelhante à ilustração abaixo:
Para que os botões contenham ícones, adicione um ImageList (paleta Win32). Nele, você pode adicionar ícones que representem as opções de Voltar, Página Inicial e Avançar. Neste artigo, foram usadas figuras capturadas na Internet em diversos sites:



Fazendo o WebBrowser acessar um site

O método Navigate() do componente WebBrowser é o responsável pela navegação. Basta passar para ele, entre parênteses, o endereço do site desejado. No nosso caso, passaremos como parâmetro o Edit1.Text, já que é ele quem contém a URL a ser acessada. Clique no Edit e, na guia Events do Object Inspector, procure o evento OnKeyDown. Este evento ocorre sempre que uma tecla no teclado é pressionada. Vamos usá-lo para que, quando o usuário pressionar ENTER sobre o Edit, o WebBrowser acesse o link desejado.  Clique duas vezes em OnKeyDown para gerar o cabeçalho para ele e, então, digite o seguinte:
//Código para o evento OnKeyDown do Edit1
  if Key = VK_RETURN then
    WebBrowser1.Navigate(Edit1.Text);
 
Já que qualquer pressionamento de tecla faria o navegador acessar o site digitado em Edit1, precisamos testar, primeiro, se a tecla pressionada foi ENTER, através da linha Key = VK_RETURN. Se não fizéssemos isso, o WebBrowser tentaria acessar o site ainda no momento da digitação do endereço.
Para os botões Voltar, Página Inicial e Avançar, respectivamente, use a codificação mostrada abaixo:
//Código para o botão Voltar
  WebBrowser1.GoBack;

//Código para o botão Página Inicial
  WebBrowser1.GoHome;

//Código para o botão Avançar
  WebBrowser1.GoForward;
 
A aparência do seu navegador deve estar, agora, semelhante a esta:

Para que os botões Voltar e Avançar funcionem sem falhas, no entanto, é necessário, acrescentar algo mais nos códigos. É que, quando não há sites para os quais voltar ou avançar, uma mensagem de "Erro não especificado" aparece na tela:

Para evitar isso, modifique o código dos botões Voltar e Avançar para que fiquem conforme a seguir:
//Novo código para o botão Voltar
  try
   WebBrowser1.GoBack;
  except

  end;


//Novo código para o botão Avançar
  try
    WebBrowser1.GoForward;

  except
  end;
No Delphi, o bloco try-except impede que, em tempo de execução, apareça qualquer mensagem de erro gerada pelos códigos em seu interior. Portanto, colocando o método GoForward e GoBack entre um try e um except, qualquer erro proveniente destas linhas não será mostrado para o usuário final.

Codificando mensagens na Barra de Status (StatusBar)

No Internet Explorer, sempre que uma página está sendo carregada, podemos observar a mensagem "Carregando ..." no rodapé da janela, da mesma forma que, ao ser finalizado o seu carregamento, vemos a mensagem "Concluído". Faremos o mesmo com nosso navegador. O WebBrowser tem eventos que permitem o tratamento adequado destas mensagens. São eles:
  • OnDownloadBegin:  evento que ocorre sempre que um item da página começa a ser carregado, seja ele uma figura, código HTML, etc.
  • OnDownloadComplete: este evento ocorre sempre que um item (figura, código HTML, etc.) terminou seu carregamento, independentemente de ter sido carregado com sucesso ou não.
  • OnDocumentComplete: este evento acontece sempre que o documento é totalmente carregado na janela do WebBrowser.
  • OnNavigateComplete2: este evento acontece antes do DocumentComplete e serve para indicar que o link desejado foi "atingido" com sucesso, mas não que esteja necessariamente carregado por completo. No entanto, serve como contraponto ao DownloadComplete, uma vez que OnNavigateComplete2 somente ocorre se o documento realmente consegue atingir e, ao menos, iniciar o carregamento da página adequadamente.
A título de exemplo, trataremos aqui os eventos OnDownloadBegin, OnDownloadComplete e OnNavigateComplete2:
//Código para o evento OnDownloadBegin
procedure TForm1.WebBrowser1DownloadBegin(Sender: TObject);
begin
  StatusBar1.SimpleText := 'Carregando ...';
end;
 
//Código para o evento OnDownloadComplete
procedure TForm1.WebBrowser1DownloadComplete(Sender: TObject);
begin
  StatusBar1.SimpleText := 'Concluído';
end;

//Código para o evento OnNavigateComplete2
procedure TForm1.WebBrowser1NavigateComplete2(Sender: TObject;
const pDisp: IDispatch; var URL: OleVariant);
begin
  StatusBar1.SimpleText := 'Concluído';
  Edit1.Text := WebBrowser1.LocationURL;
end;
Nos códigos apresentados, estamos atribuindo o texto desejado à propriedade SimpleText, da StatusBar, responsável por exibir mensagens na barra de status.
No evento OnNavigateComplete2, também é interessante acrescentar um código que atualize o endereço da barra de endereços (nosso Edit1) sempre que um link inicia seu carregamento adequadamente. Para isso, a linha Edit1.Text := WebBrowser1.LocationURL foi usada. Com ela, através da propriedade LocationURL do componente WebBrowser, conseguimos saber em qual site estamos atualmente. Se atribuirmos seu valor ao Edit1 (através de sua propriedade Text), o Edit1 mostrará a URL em que estamos naquele momento - o que todo navegador que se preza deve fazer.  Afinal, não teria cabimento você navegar para um site e a barra de endereços continuar mostrando a URL da página anterior.
 

Acrescentando botões de "Imprimir" e "Atualizar página"

Duas outra funcionalidades úteis são a de imprimir e atualizar página. A de atualizar é a mais simples. Basta adicionar um novo botão na Toolbar e, após renomeá-lo para BtAtualizar, digite o seguinte código:
//Código para o botão Atualizar
begin
  WebBrowser1.Navigate(Edit1.Text);

end;
Conforme pode-se perceber, "atualizar" uma página nada mais é do que forçar seu carregamento de novo e, para isso, basta invocarmos o método Navigate() do WebBrowser novamente.
Já para imprimir, a coisa é diferente. É necessário executar um método chamado ExecWB (presente na propriedade ControlInterface), responsável por executar comandos e passá-los ao componente WebBrowser. O método ExecWB recebe quatro parâmetros:
  • OLECMDID: este parâmetro indica qual será o comando a ser passado ao navegador em questão. Vários são reconhecidos e, dentre eles, podemos destacar: OLECMDID_PRINT, OLECMDID_SAVE, OLECMDID_NEW, OLECMDID_STOP, e outros. O que nos interessa aqui é o OLECMDID_PRINT, responsável pela impressão de documentos Web.
  • OLECMDEXECOPT: indica como executar o comando passado no primeiro parâmetro. Os valores válidos são apenas quatro:  OLECMDEXECOPT_DODEFAULT, OLECMDEXECOPT_PROMPTUSER, OLECMDEXECOPTDONTPROMPTUSER e OLECMDEXECOPT_SHOWHELP. Se passarmos o primeiro valor, o comando será executado da maneira padrão; o segundo valor pede que o usuário seja perguntado sobre o que deseja fazer; o terceiro diz para não questionar o usuário, e o último valor diz para mostrar a caixa de diálogo de ajuda sobre o comando, mas sem executá-lo.
  • pvaIn: este parâmetro recebe uma matriz de entrada do tipo Variant. O melhor a fazer aqui é criar uma variável do tipo OleVariant e passá-la como parâmetro.
  • pvaOut: este parâmetro recebe o resultado do comando executado - se houver algum resultado. Também deve-se criar, aqui, uma variável do tipo OleVariant para armazenar qualquer que seja o resultado retornado pelo comando.

Dessa maneira, o nosso botão Imprimir pode ter o seguinte aspecto:
//Código presente no botão Imprimir
procedure TForm1.BtImprimirClick(Sender: TObject);
var
  Valor1, Valor2: OleVariant;
begin
  WebBrowser1.ControlInterface.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, Valor1, Valor2) ;
end;
O código acima usa o comando OLECMDID_PRINT, para imprimir o documento, e utiliza o parâmetro OLECMDEXECOPT_PROMPTUSER para que a caixa de diálogo de impressão seja apresentada ao usuário. Caso isso não seja desejado, pode-se passar OLECMDEXECOPT_DONTPROMPTUSER.


Salvando um documento da Internet

Para finalizar, vejamos como utilizar o WebBrowser para salvar a página atualmente vista na tela. Aqui será necessário utilizar a unit ActiveX do Delphi. Coloque-a, então, na cláusula uses do seu programa. Coloque também um objeto SaveDialog (paleta Dialogs) para que o usuário possa informar qual será o nome de destino do arquivo.
Também precisaremos lidar com um tipo específico e mais complexo de dados chamado COM. De uma maneira geral, COM (Component Object Model) é uma plataforma da Microsoft criada em 1993 que permite a comunicação entre processos e a criação dinâmica de objetos independente da máquina ou arquitetura utilizada.
A plataforma COM traz o que se chama de Interface, uma característica que permite trabalhar com diversos recursos de software sem que seja necessário conhecer detalhes sobre como ele foi concebido. Um bom exemplo da utilização de interfaces é o do próprio sistema operacional que, através de uma interface de programação de aplicativos, permite que os programas utilizem diversos recursos (tais como memória, CPU,  etc.) sem que os seus detalhes de implementação sejam conhecidos do programador. Este esquema isola e protege o sistema operacional de eventuais erros cometidos pela aplicação.
A plataforma COM especifica várias interfaces-padrão usadas para permitir a comunicação entre componentes. A principal delas é a IUnknown, que traz os principais métodos necessários para lidar com o sistema e da qual todas as demais são derivadas. Nós iremos utilizar a interface IStream, que é exposta por componentes que utilizam fluxo de dados e que possui os métodos Read e Write, para realizar a leitura e a escrita do fluxo de dados.
Portanto, para gravar em disco uma página Web, precisamos da interface IStream, que implementa os métodos de leitura e escrita, e de uma IPersistStreamInit que, de certo modo, faz do documento web um objeto "gravável". Também precisaremos de um tipo de variável chamada TFileStream, que permite que seja atribuído um nome de arquivo aos dados salvos via IStream. O código do botão para salvar ficaria assim:

procedure TForm1.BtSalvarComoClick(Sender: TObject);
 var
 
PersistStream: IPersistStreamInit;
  Stream: IStream;
  FileStream: TFileStream;
begin
 if not Assigned(WebBrowser1.Document) then
  begin
   application.messagebox('Documento HTML não carregado','Documento Web',16);
   Exit;
  end;

 if SaveDialog1.Execute then begin
  PersistStream := WebBrowser1.Document as IPersistStreamInit;
  FileStream := TFileStream.Create(SaveDialog1.FileName, fmCreate);
  try
   Stream := TStreamAdapter.Create(FileStream, soReference) as IStream;
   if Failed(PersistStream.Save(Stream, True)) then
   application.messageBox('Falha ao salvar arquivo HTML!','Salvar arquivo',16);
  finally
   FileStream.Free;
  end;
 end;

end;

Por conter uma codificação muito diferente das demais realizadas até aqui, vale ainda algumas observações. A primeira linha logo após o begin, onde lê-se if not Assigned(WebBrowser1.Document)...  diz à função que, se não houver nenhum documento web atribuído ("assigned") à propriedade Document do WebBrowser é porque não há nenhuma página carregada e, então, uma mensagem de erro deve ser exibida. Mais ao final, onde lê-se if Failed(PersistStream.Save(Stream, True))...  estamos verificando se houve alguma falha no salvamento dos dados da página web em disco, através da função Failed  - que retorna true se os dados não foram salvos corretamente, e false se tudo transcorreu sem problemas.
Share:

0 comentários:

Postar um comentário

Tecnologia do Blogger.