quarta-feira, 31 de outubro de 2012

Como Ordenar uma Lista de Objetos (TObjectList)

Ordenação  de TObjectList

Muitas vezes utilizamos listas de objetos (TObjectList) para agrupar clientes, contatos, produtos, etc.
Pode ser que os dados sejam adicionados a lista sem uma ordenação lógica, ordenação esta que pode vir a ser necessária.
A classe TObjectList possui o método Sort que possui a seguinte assinatura:

procedure Sort(Compare: TListSortCompare);

O parâmetro Compare é do tipo TListSortCompare que deve ser uma função com a seguinte assinatura

TListSortCompare = function (Item1, Item2: Pointer): Integer;

Como vocês podem ver, para ordenar a lista será necessário criar uma função de ordenação utilizando a regra que desejarmos.

Exemplo de função de ordenação

Para exemplificar vou criar uma classe Item, uma lista de Itens(TItemList) e duas funções de ordenação.


type
  TItem = class(TObject)
  private
    FName: string;
    FID: Integer;
    procedure SetID(const Value: Integer);
    procedure SetName(const Value: string);
  public
    property ID   : Integer read FID write SetID;
    property Name : string read FName write SetName;
  end;

  TItemList = class(TObjectList)
  public
    function Add(AObject: TItem): Integer;
  end;

function SortAscending(Item1, Item2: Pointer): Integer;
var Obj1 : TItem;
    Obj2 : TItem;
begin
  Obj1 := TItem(Item1);
  Obj2 := TItem(Item2);
  if Obj1.ID > Obj2.ID then
    Result := +1
  else
    if Obj1.ID < Obj2.ID then
      Result := -1
    else
      Result := 0;
end;

function SortDescending (Item1, Item2: Pointer): Integer;
var Obj1 : TItem;
    Obj2 : TItem;
begin
  Obj1 := TItem(Item1);
  Obj2 := TItem(Item2);
  if Obj1.ID > Obj2.ID then
    Result := -1
  else
    if Obj1.ID < Obj2.ID then
      Result := +1
    else
      Result := 0;
end;

Agora um exemplo de utilização das classes e funções. Será utilizado um laço para gerar aleatoriamente 10 ID diferentes para preencher um componente Memo na ordem de geração e depois em Ordem Crescente e Decrescente.

var Item : TItem;
    List : TItemList;
    idx  : Integer;
    ID   : Integer;
begin
  Memo1.Lines.Clear;
  Memo1.Lines.Add('Ordem de Geração');
  List := TItemList.Create;
  for idx := 1 to 10 do
  begin
    ID := Random(99) + 1;
    Item := TItem.Create;
    Item.ID := ID;
    Item.Name := Format('Item%.3d', [ID]);
    List.Add(Item);
    Memo1.Lines.Add(Format('ID=%.3d', [Item.ID]));
  end;

  Memo1.Lines.Add('=====');
  Memo1.Lines.Add('Ordem Ascendente');
  List.Sort(SortAscending);
  for idx := 0 to List.Count -1 do
  begin
    Item := List[idx] AS TItem;
    Memo1.Lines.Add(Format('ID=%.3d', [Item.ID]));
  end;

  Memo1.Lines.Add('=====');
  Memo1.Lines.Add('Ordem Descendente');
  List.Sort(SortDescending);
  for idx := 0 to List.Count -1 do
  begin
    Item := List[idx] AS TItem;
    Memo1.Lines.Add(Format('ID=%.3d', [Item.ID]));
  end;
end;


Este código irá gerar uma saída semelhante a esta:
Ordem de Geração
ID=063
ID=090
ID=078
ID=009
ID=067
ID=026
ID=045
ID=083
ID=027
ID=073
=====
Ordem Ascendente
ID=009
ID=026
ID=027
ID=045
ID=063
ID=067
ID=073
ID=078
ID=083
ID=090
=====
Ordem Descendente
ID=090
ID=083
ID=078
ID=073
ID=067
ID=063
ID=045
ID=027
ID=026
ID=009

Como vocês viram é simples gerar a função de ordenação, seria possível ordenar por data, nome ou qualquer outra propriedade presente nos Objetos da Lista. Até a próxima :D

0 comentários:

segunda-feira, 29 de outubro de 2012

How to call another application from a service

This is a tip of Delphi, but should be the same in other languages

Say you have the following file structure:

folder
-> serviceapp.exe
-> application.exe

If you want to run the application.exe from a function in serviceapp.exe such as:

WinExec (PChar ('application.exe'), SW_MINIMIZE);

This code will not work even both being in the same folder as the service does not run from the directory where the file serviceapp.exe is.

To work you need the following:

ChDir (ExtractFilePath (Application.ExeName));
WinExec (PChar ('application.exe'), SW_MINIMIZE);

The procedure ChDir () change the current directory where the process is active.
Another option is:

WinExec (PChar (ExtractFilePath (Application.ExeName) + 'application.exe'), SW_MINIMIZE);

This way you will run the application.exe file using the full path to the executable.
But in this case the  application.exe still running from another folder, then the option Chdir () is better.

Until next tip: D

0 comentários:

Como chamar programa a partir de um serviço

Esta é uma dica de Delphi, mas deve ser o mesmo em outras linguagens
Digamos que você possua a seguinte estrutura de arquivos:

pasta
-->serviço.exe
-->arquivo.exe

Se você quiser executar o arquivo.exe a partir de uma função de serviço.exe como por exemplo:

WinExec(PChar('arquivo.exe'), SW_MINIMIZE);

Este código não irá funcionar mesmo ambos estando na mesma pasta, pois o serviço não executa do diretório onde está o arquivo serviço.exe.

Para funcionar é necessário o seguinte procedimento:

ChDir(ExtractFilePath(Application.ExeName));
WinExec(PChar('arquivo.exe'), SW_MINIMIZE);

A procedure ChDir() serve para mudar o diretório atual onde o processo está ativo.
Outra opção é:

WinExec(PChar(ExtractFilePath(Application.ExeName) + 'arquivo.exe'), SW_MINIMIZE);

Desta maneira é executado o programa arquivo.exe utilizado o caminho completo do executável.
Mas neste caso arquivo.exe ainda é executado em outra pasta e não onde este se encontra, então a opção Chdir() ainda é mais recomendada.
Até a próxima dica :D

0 comentários:

Debugando no Delphi

Este post é sobre alguns macetes do Debugger do Delphi que ajudam muito na hora de encontrar um erro ou mesmo corrigi-lo.

Erro de Acesso a Memória.


Esse tipo de erro é muito chato.
Primeiramente mostra uma mensagem muito assustadora para o usuário leigo.
Para o desenvolvedor a mensagem não permite saber o que ocasionou o erro.
Felizmente o Delphi permite encontrar a causa do erro com facilidade.
Basta acessar o menu Search -> Find Error.
Na caixa de diálogo que irá aparecer basta digitar o endereço que apareceu quando ocorreu o erro de acesso a memória. Neste exemplo: 0044E292 e clicar no botão OK e o Delphi irá para a linha onde o erro foi gerado.

Evaluate/Modify
Esta opção ajuda muito na hora de descobrir a causa de algum erro ou mesmo alterar o valor de uma variável durante a execução do programa.
Quando a execução do programa estiver parada, por exemplo, definindo um breakpoint.
Acesse o menu Run -> Evaluate/Modify. Este comando irá exibir a seguinte caixa de diálogo
.


Na caixa de edição Expression você pode digitar uma expressão. Por exemplo, supondo que você tenha uma variável linha do tipo string que contém uma linha lida de um arquivo texto e deseja saber o tamanho desta linha. Digite length(linha) e clique em Evaluate. O resultado aparecerá no campo Result.
Agora digamos que você deseja alterar o valor contido nesta variável linha. No campo Expression digite linha e clique em Evaluate. No campo Result aparecerá o valor contido na variável. Agora na caixa de edição New Value digite o novo valor da variável e clique em Modify. Muito útil quando, por exemplo, você descobre a causa daquele laço infinito e deseja continuar testando o programa. Basta alterar o resultado do teste feito no laço e continuar executando o programa normalmente.

0 comentários:

Blogger Template by Clairvo