sábado, 5 de setembro de 2009

Mostrando progresso sql no delphi

{Esta dica serve para mostrar o progresso de diversas atividades que o BDE executa, como: * Criação de tabelas

* Criação de índices para tabelas

* Reestruturação de tabelas

* Execução de queries (já comentado)

* alguma outra coisa que no momento não me ocorre... :))

Teoria

Segundo o help do Delphi, "o TBDECallback é um wrapper para uma função de callback do BDE. Com ele é possível instruir o BDE para que o mesmo execute algumas tarefas em resposta a eventos que ocorram durante uma chamada de uma função do BDE. " - Fim do plagio do arquivo de help.

O tipo de callback depende de um parâmetro CBType que é fornecido no momento da criação do TBDECallback. E, entre os diversos valores que o CBType pode apresentar, existe um que muito nos interessa; o cbGENPROGRESS.

:))

Assim, você deveria criar uma função de callback do tipo cbGENPROGRESS chamada AtualizaGauge e indicar que a mesma é que devera ser executada "entre cada respiração" do BDE. Na rotina AtualizaGauge, o BDE iria te informar o percentual de progresso da tarefa .

O que você faria nessa rotina ? Simples... atualizar o Gauge / ProgressBar.

Tudo muito bonito, tudo muito comovente, mas agora vamos para o lado pratico...

Pratica

Para que o BDE possa informar o progresso da tarefa, ele precisa obter essa informação da base de dados que esta sendo utilizada. Acontece que, por razoes diferentes, nem sempre ele é capaz de saber o PERCENTUAL da tarefa. Numa copia de registros de uma tabela para outra, ele pode saber que já foram copiados 270 registros, mas não saber que esse esforço representa 36 % de todos os registros que serão copiados.

Assim sendo, na função de callback que será criada, receberemos um parâmetro do tipo pCBPROGRESSDesc, que por sua vez é um ponteiro para uma estrutura que contem duas informações:

iPercentDone => percentual do serviço realizado

szMsg => texto descrevendo o progresso do serviço.

Como usar esses parametros ? Simples: sempre que o iPercentDone for negativo, você devera considerar o texto descrito no campo szMsg. Se for igual ou maior que zero, então você devera considerar o valor do próprio iPercentDone.

Uma boa noticia para quem se preocupa com as mensagens que aparecem em inglês, quando se quer na verdade mostrá-la em português: a mensagem fornecida por szMsg devera sempre aparecer no formato

<:>

.....

Exemplo:

Records copied: 170

Assim, você pode procurar pelos dois pontos ":" e pegar o valor que vem a seguir para montar sua própria informação em português.

Pessoalmente, ate agora nunca obtive um iPercentDone positivo. Li no newsgroup da Borland que poucas bases de dados eram capazes de informar o real percentual para o BDE. Se não me engano, o Sybase era um deles... não ESTOU CERTO DISSO.

Vamos para um exemplo pratico ? Crie um projeto novo, e coloque um:

TQuery, TButton, TProgressBar e TLabel.

Sua query deve ser montada para abrir uma tabela razoavelmente grande, de moro que a operação de abertura demore um pouco.

Agora vamos aos códigos:

1) Acrescente a unit BDE no seu USES da unit.

2) Acrescente algumas declarações na declaração do seu Form:}


type
TForm1 = class(TForm)
... (bla bla bla)
private
{ Private declarations }
FCBPROGRESSDesc: pCBPROGRESSDesc;
FProgressCallback: TBDECallback;
function GetDataCallback(CBInfo: Pointer): CBRType;
public
{ Public declarations }
end; //No evento OnCreate do seu Form:


procedure TForm1.FormCreate(Sender: TObject);
begin
fcbprogressdesc := AllocMem(SizeOf(CBPROGRESSDesc));
fprogresscallback := TBDECallback.Create(Self, Query1.Handle,
cbGENPROGRESS, fcbprogressdesc, SizeOf(CBPROGRESSDesc),
getdatacallback, True);
end; {Percebam que no segundo parâmetro do Create do callback, eu coloquei Query1.Handle.

Caso você queira usar isso numa TTable, coloque Table1.Handle.

E se quiser que essa função de callback seja chamada para todos os "progressos" de qualquer componente DataSet, você deixa esse parâmetro como

NIL.

No evento OnDestroy do Form:}

procedure TForm1.FormDestroy(Sender: TObject);


begin
fprogresscallback.Free;
FreeMem(FCBPROGRESSDesc, SizeOf(CBPROGRESSDesc));
end; //E agora, a tão falada função de callback:


function TForm1.getdatacallback(CBInfo: Pointer): cbrtype;
begin
Result := cbrCONTINUE;
with pcbprogressdesc(CBInfo)^ do
begin
if iPercentDone < 0 then
begin
Label1.Caption := szMsg;
Label1.Refresh;
ProgressBar1.StepIt; {Apenas para ficar rodando o gauge}
end
else
ProgressBar1.Position := iPercentDone;
end;
end; {Caso você receba uma mensagem de erro informando que não foi possível inicializar o BDE (o que provavelmente acontecera, pois você esta criando uma função de callback do BDE, quando ate então nenhuma tabela havia sido aberta), vá no DPR do seu projeto (Menu View -> Project Source) e faça o seguinte:

1) Acrescente a unit BDE no uses do projeto.

2) Acrescente a instrução

DbiInit(nil);

apos a instrução Application.Initialize;

Isso deve resolver o problema. }

Nenhum comentário:

Postar um comentário