sábado, 30 de abril de 2011

Exibindo as propriedades do arquivo

A dica abaixo apresenta o código de implementação para exibir na tela uma janela padrão Windows de propriedades do arquivo.

Para implementar este procedimento é necessário acrescentar a unit ShellAPI.As propriedades do arquivo são armazenadas numa estrutura chamada TShellExecuteInfo, que corresponde a um registro com os campos: tamanho do arquivo (cbSize), atributos (fMask), nome (lpFile) , shell (lpVerb) e modo de apresentação da janela (nShow).O primeiro passo do procedimento é zerar todas a propriedades da Shell ( FillChar(S,SizeOf(S),0) ), segundo passo é atualizar estas propriedades (With S do ) em relação ao arquivo indicado (Arq :String) e o terceiro passo é abrir a janela de propriedades com os valores atualizados (ShellExecuteEx(@S)).

Código Completo:

Procedure Propriedades(Arq:String);
Var
s:TShellExecuteInfo;
Begin
FillChar(S,SizeOf(S),0);
With S do Begin
cbSize := SizeOf(S);
fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_INVOKEIDLIST or SEE_MASK_NOCLOSEPROCESS;
wnd := Handle;
lpVerb := 'properties';
lpFile := Pchar(Arq);
nShow := sw_ShowNormal;
End;
ShellExecuteEx(@S);
End;

Criando um diretório

Para criar um diretório você precisa usar a função ForceDirectories, o exemplo a baixo testa se não existe um diretório e cria o diretório apartir de uma variável string testando se o diretório já existe

Unit
 
FileCtrl
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Dir: string;
begin
Dir := 'C:\APPS\SALES\LOCAL';
 
if not DirectoryExists(Dir) then
  ForceDirectories(Dir);
  Label1.Caption := Dir + ' foi criado';
end;

terça-feira, 26 de abril de 2011

Colocar uma barra de progresso na inicialização do sistema

É bem simples, trata-se de abrir por código todas as tabelas na entrada do programa, portanto deixe todas as tabelas fechadas no datamodule.

procedure DataModule.OnCreate;
var Tabela, i: Integer;
begin
  Tabela := 0;
  for I := 0 to ComponentCount -1 do
    if Components[I] is TTable then
      with TTable(Components[I]) do
        if (Tag = 9) and not Active then  // Tag = 9 identifica as tabelas à serem abertas
         try
           Inc(Tabela);  // contador das tabelas q já foram abertas.
           lblInfo.Caption := Format('Abrindo as Tabelas (%d/%d)', [Tabela, Total]);
           {aqui, informo à uma label o andamento do processo, usei o formato totalTabelasAbertas/TotalàAbrir, pode-se trocar para porcentagem ou até usar o ProgressBar.}
           lblInfo.Refresh; // vital para atualizar a tela durante o processo.
           Application.ProcessMessages;
           Open;
        except
   Raise; // quem estiver a fim, pode-se colocar aqui uma verificação, se deu zebra e a zebra é indice corrompido, rodar rotina de recriação de indice da tabela.
end;

Alternando Bitmaps no Fundo de um Form.

Um leitor perguntou recentemente sobre imagens de fundo em Forms.... Apesar de já se ter escrito diversos artigos sobre este tópico, sua questão tinhas algumas novidades. Primeiramente, ele desejava que o fundo se alternasse periodicamente.
Essencialmente, a solução para isto seria a aplicação de outros artigos similares. Em primeiro lugar, para resolver a questão de se ter diversas imagens, os bitmaps devem ser carregados em um array quando o Form for criado. A mudança periódica da imagem s
Finalmente, para tratar do assunto "não leia as imagens do disco", recorremos aos resources. Um arquivo de resource é apenas um caminho para empacotar muito bem qualquer tipo de dados que será anexado ao executável durante o processo de Linkedição. Para o
BITMAP1 BITMAP IMAGE1.BMP
BITMAP2 BITMAP IMAGE2.BMP
BITMAP3 BITMAP IMAGE3.BMP
BITMAP4 BITMAP IMAGE4.BMP
BITMAP5 BITMAP IMAGE5.BMP
A primeira parte de cada linha é o identificador que você utilizará no código para capturar uma imagem em particular. A segunda parte é o tipo de resource (neste caso, bitmap). E a última parte é o nome do arquivo que deve ser utilizado para a imagem. Ist
{$R MYBMPS.RES}
Quando o executável está sendo linkeditado (um passo antes da compilação), o resource será automaticamente anexado ao executável. Para carregar as imagens do resource no array de bitmaps no programa, fiz simplesmente:
    for a := 1 to NumBmps do
    begin
       Bmps[a] := TBitmap.Create;
       Bmps[a].LoadFromResourceName(hInstance,'BITMAP'+IntToStr(a));
    end;
É basicamente isto... A seguir a listagem da Unit principal:
unit Unit1a;
interface
uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    ExtCtrls, StdCtrls;
const
    NumBmps = 5;
type
    TForm1 = class(TForm)
        Timer1: TTimer;
        Edit1: TEdit;
        CheckBox1: TCheckBox;
        ListBox1: TListBox;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormPaint(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
    private
       Bmps : Array[1..NumBmps] of TBitmap;
       SelectedBmp : Integer;
    public
    { Public declarations }
    end;
var
    Form1: TForm1;
implementation
{$R *.DFM}
{$R MYBMPS.RES}
procedure TForm1.FormCreate(Sender: TObject);
var
    a : Integer;
begin
    for a := 1 to NumBmps do
    begin
        Bmps[a] := TBitmap.Create;
        Bmps[a].LoadFromResourceName(hInstance,'BITMAP'+IntToStr(a));
    end;
    SelectedBmp := 1;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
    a : Integer;
begin
    for a := 1 to NumBmps do Bmps[a].Free;
end;
procedure TForm1.FormPaint(Sender: TObject);
var
    x,y,w,h : Integer;
begin
    w := Bmps[SelectedBmp].Width;
    h := Bmps[SelectedBmp].Height;
    for x := 0 to (Width div w) do
        for y := 0 to (Height div h) do
            Canvas.Draw(x*w,y*h,Bmps[SelectedBmp]);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
    Inc(SelectedBmp);
    if SelectedBmp > NumBmps then SelectedBmp := 1;
    Paint;
end;end.

Técnicas de depuração em Delphi e Prevenção de Bug


Muitas vezes pegamos um sistema legado de outro programador para realizarmos implementação de novas funcionalidades ou corrigir eventuais "bugs". Neste caso você vai precisar depurá-lo para encontrar os "bugs". O Delphi oferece ótimas ferramentas de depuração e quando você sabe como usá-las, você vai economizar muito tempo para corrigir o "bug" e chegar no resultado desejado
Neste caso quero indicar um tutorial que encontrei e ajudou quando o assunto era depuração de programas.
Aqui está o conteúdo:

Project options - antes que você possa começar a utilizar as ferramentas depurador do Delphi, você tem que certificar-se de todas as configurações necessárias são definidas opções depurador .

Breakpoints - Quando pressionar a tecla F5 ou clicando na barra esquerda do seu editor você pode adicionar uma linha vermelha para a sua fonte. Esta linha de origem terão um ponto de interrupção. Ao executar o programa, a execução irá parar quando ele passa a linha de origem. Agora você pode seguir em sua origem, usando algumas teclas de função.

Call stack - a janela Call Stack exibe as chamadas de função que o trouxe para a sua localização atual no programa e os argumentos passados para cada chamada de função.

Local variables - essa janela vai mostrar todas as variáveis locais e o seu valor atual no atual função ou procedimento.

Watches - você adicionar um Watches para controlar os valores das variáveis do programa ou expressões como você passar por cima ou em código de rastreamento.

Idéias para criar os seus próprios recursos de depuração Prevenção Bug Try-Finally Gotchas Try-Except Gotchas

domingo, 17 de abril de 2011

Adicionando o sistema no menu de contexto do Windows Explorer


Aqui vai uma dica para adicionar um item ao menu de contexto do Windows Explorer, exibido ao clicarmos com o botão direito do mouse sobre uma pasta.

Quando o usuário clica com o botão direito sobre uma pasta no Windows Explorer (ou em um componente TShellTreeView) um menu de contexto é exibido. Entre os itens padrões é possível adicionar um para a sua própria aplicação. Quando o usuário clicar neste seu item, o programa será iniciado e o caminho daquele diretório será passado como parâmetro.

A procedure a seguir adiciona uma entrada no registro do Windows para "registrar o programa" como um comando válido no menu de contexto:

procedure EnsureShellFolderPopupItem(const itemName: string);
begin
  with TRegistry.Create do
  try
    RootKey := HKEY_CLASSES_ROOT;
    if OpenKey('Directory\shell', true) then
    begin
      if OpenKey(itemName+'\command', true) then
        WriteString('', '"'+Application.ExeName+'" "%1"');
    end;
  finally
    Free;
  end;
end;

Este código fará a adição de uma chave na seguinte forma:

HKEY_CLASSES_ROOT\Directory\shell\itemName

Onde itemName será passado por parâmetro à função (vide código abaixo) e que na verdade será o texto de exibição no menu de contexto. Seu valor será o caminho do programa e o %1, para indicar que a pasta clicada será enviada por parâmetro à aplicação:

;@="c:\...\Project1.exe" "%1" - Onde "c:\...\Project1.exe" é o local do seu executável.

Agora no evento onCreate do Form, façamos:

procedure TForm1.FormCreate(Sender: TObject);
begin
  //certifica que nosso item está no menu de contexto de diretórios
  //não é necessário chamar sempre, mas para testes está ok!
  EnsureShellFolderPopupItem('Processar com Meu Programa');

  //exibe qual a pasta que foi selecionada para processamento
  if ParamCount > 0 then
    ShowMessage('Pasta selecionada: ' + ParamStr(1))
  else
    ShowMessage('Sistema iniciado diretamente');
end;

Para testar, rode o programa pelo Delphi para que seja processada a procedure EnsureShellFolderPopupItem. Você receberá a mensagem "Sistema iniciado diretamente". Em seguida, feche o programa e clique com o botão direito sobre qualquer diretório no seu computador.

quinta-feira, 14 de abril de 2011

Conhecendo a classe Exception

Fonte: www.activedelphi.com.br

Durante a execução de uma aplicação é muito comum ocorrer erros que acabam atrapalhando sua execução, tais erros são denominados exceções. Por exemplo, temos uma função responsável em dividir dois valores, exemplificada abaixo:
function Divisao(Valor1,Valor2: Double): Double;
begin
  Result := Valor1/Valor2;
end;

Se atribuirmos ao parâmetro Valor2 o numero 0, irá ocorrer uma exceção e uma mensagem será exibida.

A mensagem nos informa que ocorreu uma exceção do tipo "EZeroDivide" com a mensagem "Floating point division by zero" (Divisão de ponto flutuante por zero), ou seja, tentamos dividir um valor por zero, o que na matemática é uma operação indeterminada.

O problema é que na maioria das vezes tais exceções provocam o encerramento da aplicação de forma brusca, que é muito desagradável, principalmente quando seu programa exige que determinadas informações sejam atualizadas, como salvar alterações feitas em bancos de dados. Para resolver este problema podemos utilizar a classe Exception, através das cláusulas try...except...end, de acordo com a sintaxe abaixo:
try
  //Insira aqui o bloco de comandos
except
  //Insira aqui o bloco de comandos que deverá ser executado caso ocorra alguma
  //exceção no código acima
end;
Você também pode usar o bloco try...finally...end:

try
  //Insira aqui o bloco de comandos
finally
  //De forma análoga, insira aqui o bloco de comandos que deverá ser executado caso
  //ocorra alguma exceção ou interrupção (exit / abort) no código acima
end;
Antes de prosseguirmos vamos conhecer um pouco mais a classe Exception.

A classe Exception é codificada na Unit SysUtils, é derivada da classe TObject e compõe a classe-base para todas as outras que manipulam exceções. Uma curiosidade é que a classe não segue o padrão do Delphi, onde o nome das classes deve ser precedido pela letra "T". Ela possui dois campos internos:

- um deles é o FMessage, um campo do tipo string(texto) que define a mensagem que será exibido na caixa de diálogo quando a exceção é gerada.
- o outro é o FHelpContext, do tipo integer(inteiro) que guarda o índice que identifica o tópico do arquivo help on-line associado a essa classe.

Voltando a nossa função "divisao", podemos tratá-la da seguinte forma:
function Divisao(Valor1,Valor2: Double): Double;
begin
  try
    Result := Valor1/Valor2;
  except
    ShowMessage('Valores incorretos!');
  end;
end;
Também podemos verificar qual o tipo de exceção foi gerado, usando o comando:

  on < tipo de exceção> do
Dessa forma é possível definir um bloco de comandos para cada exceção que sua aplicação possa gerar, permitindo um tratamento individual. Poderíamos redefinir a função como abaixo:

function Divisao(Valor1,Valor2: Double): Double;
begin
  try
    Result := Valor1/Valor2;
  except
    on EZeroDivide do
      ShowMessage('Divisão por zero!');
  end;
end;
Abaixo segue uma tabela com algumas exceções, claro que existe um número muito maior e é impossível lista-las. O objetivo desse artigo foi introduzir os conceitos referentes à classe Exception para quem nunca teve contato com ela.

Exceção
Significado
EZeroDivide
Divisão de um número real por zero
EDivByZero
Divisão de um número inteiro por zero
ERangeError
O limite de um número inteiro foi excedido
EIntOverFlow
O limite do resultado de uma operação com número inteiro foi excedido
EOverFlow
O limite do resultado de uma operação com numero real foi excedido
EInvalideOp
Operação inválida
EAccessViolation
Acesso violado
EDataBaseError
Erro genérico no banco de dados
EDBEngineError
Problema com a BDE
EOutOfMemory
Memória insuficiente


Você pode conferir mais sobre o uso dos comandos Try..Except e Try..Finally nesta série de artigos feita pelo João Marcos:
Try..Except..Finally - Parte 01 
Try..Except..Finally - Parte 02 
Try..Except..Finally - Final

Curso de Delphi: 7.Consultas SQL