Fórum Usar propriedade de outra classe em componente. #295450

14/09/2005

0

Galera tô criando um componente para efetuar download com base naquele artigo que mandei a alguns dias para o Portal.

[url=http://www.clubedelphi.net/Novo/Colunistas/AdrianoSantos/01.asp]Download com Progresso[/url]

Bom, criei uma classe para acessar a interface IBindStatusCallback que será usada para atualizar a barra de progresso. E na classe principal do componente crie uma propriedade ProgressBar (TProgressBar) e uma LabelInfo (TLabel). Essas propriedades, quando configuradas, vão ser atualizadas pelo componente, mas não consigo acessá-las pelo evento onProgress da Interface, juro que tô viajando na maionese aki. Segue alguns trechos do fonte abaixo:


...

type
  TOpcoesDown = (odCriarDestino, odAvisarSobrepor, odAvisarFinalizacao);
  TOpcoes = Set of TOpcoesDown;

type
  TMeuObjetoInterface = class(TInterfacedObject, IBindStatusCallback)
  public
    function OnStartBinding(dwReserved: DWORD; pib: IBinding): HResult; stdcall;
    function GetPriority(out nPriority): HResult; stdcall;
    function OnLowResource(reserved: DWORD): HResult; stdcall;
    function OnProgress(ulProgress, ulProgressMax, ulStatusCode: ULONG;
      szStatusText: LPCWSTR): HResult; stdcall;
    function OnStopBinding(hresult: HResult; szError: LPCWSTR): HResult;
      stdcall;
    function GetBindInfo(out grfBINDF: DWORD; var bindinfo: TBindInfo): HResult;
      stdcall;
    function OnDataAvailable(grfBSCF: DWORD; dwSize: DWORD; formatetc:
      PFormatEtc;
      stgmed: PStgMedium): HResult; stdcall;
    function OnObjectAvailable(const iid: TGUID; punk: IUnknown): HResult;
      stdcall;
  end;

type
  TDcDownProgress = class(TComponent)
  private
    { Private declarations }
    FProgress: TProgressBar;
    FDestino: String;
    FOrigem: String;
    FOpcoes: TOpcoes;
    FLabelInfo: TLabel;
    function GetDestino: String;
    function GetOrigem: String;
    procedure SetDestino(const Value: String);
    procedure SetOrigem(const Value: String);
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy;override;
    function Execute : Boolean;
  published
    { Published declarations }
    property Origem : String read GetOrigem write SetOrigem;
    property Destino : String read GetDestino write SetDestino;
    property ProgressBar : TProgressBar read FProgress write FProgress;
    property Opcoes : TOpcoes read FOpcoes write FOpcoes default [odCriarDestino];
    property LabelInfo: TLabel read FLabelInfo write FLabelInfo;
  end;

...

function TDcDownProgress.Execute: Boolean;
var
  MeuEstatus: TMeuObjetoInterface;
begin
  if Trim(FDestino) = ´´ then
  begin
    MessageDlg(´O destino do download não foi especificado.´, mtError, [mbOk], 0);
    Exit;
  end;
  if (not DirectoryExists(FDestino)) and (odCriarDestino in Opcoes) then
    ForceDirectories(FDestino)
  else
  begin
    MessageDlg(´O diretório destino não existe.´, mtError, [mbOk], 0);
    Exit;
  end;
  {Aqui inicia o Download}
  MeuEstatus := TMeuObjetoInterface.Create;
  {Testa se foi configurado um ProgressBar e um Label}
  if (not (FProgress = Nil)) and (not (FLabelInfo = Nil)) then
    UrlDownloadToFile(nil, PChar(FOrigem), PChar(FDestino), 0, MeuEstatus)
  else
    UrlDownloadToFile(nil, PChar(FOrigem), PChar(FDestino), 0, nil);
  {testa se precisa dar mensagem final}
  if odAvisarFinalizacao in Opcoes then
    Messagedlg(´Download concluído´, mtInformation, [mbOk],0);
end;

...

function TMeuObjetoInterface.OnProgress(ulProgress, ulProgressMax,
  ulStatusCode: ULONG; szStatusText: LPCWSTR): HResult;
begin
   //aqui vai atualizar a propriedade ProgressBar e Label.
end;

...

end.



Adriano Santos

Adriano Santos

Responder

Posts

14/09/2005

Massuda

Crie na classe TMeuObjetoInterface membros/propriedades para receber a referência ao ProgressBar e ao Label. No seu código, depois de criar o objeto da classe TMeuObjetoInterface, atribua os valores desses membros/propriedades e os utilize no seu método TMeuObjetoInterface.OnProgress.


Responder

Gostei + 0

14/09/2005

Adriano Santos

Crie na classe TMeuObjetoInterface membros/propriedades para receber a referência ao ProgressBar e ao Label. No seu código, depois de criar o objeto da classe TMeuObjetoInterface, atribua os valores desses membros/propriedades e os utilize no seu método TMeuObjetoInterface.OnProgress.


[b:7fa66375da]Massuda[/b:7fa66375da], eu entendi o que quis dizer, mas confesso que nunca fiz e não sei fazer...vou tentar aki, qualquer coisa eu grito.

valeu


Responder

Gostei + 0

14/09/2005

Massuda

[quote:a25f51bbae=´Adriano Santos´]...mas confesso que nunca fiz e não sei fazer...[/quote:a25f51bbae]É exatamente o que você fez com TDcDownProgress.ProgressBar e TDcDownProgress.LabelInfo :wink:


Responder

Gostei + 0

14/09/2005

Adriano Santos

Cara, aquilo deu certo...baba...valeu...mas meu, agora estou num dilema com outra coisa...da uma olhda que não to conseguindo colocar as ideias no lugar.

Criei um tipo enumerado e estou tentando usá-lo, mas fica sempre vazio...acho que to esquecendo de fazer alguma coisa...valeu

type
  TOpcoesDown = (odCriarDestino, odAvisarSobrepor, odAvisarFinalizacao);
  TOpcoes = Set of TOpcoesDown;
...
  private
    FOpcoes: TOpcoes;
...
procedure SetOpcoes(const Value: TOpcoes);
...
property Opcoes : TOpcoes read FOpcoes write SetOpcoes default [odCriarDestino];
...
...
...

constructor TDcDownProgress.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

...

procedure TDcDownProgress.SetOpcoes(const Value: TOpcoes);
begin
  FOpcoes := Value;
end;




Responder

Gostei + 0

14/09/2005

Massuda

[quote:557c3de263=´Adriano Santos´]Criei um tipo enumerado e estou tentando usá-lo, mas fica sempre vazio...[/quote:557c3de263]você quer dizer que ele começa vazio?

Se esse for o problema, inicie a propriedade no construtor do componente...
constructor TDcDownProgress.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FOpcoes := [odCriarDestino];
end;

A palavra reservada [b:557c3de263]default[/b:557c3de263] tem um pegadinha... na verdade ela é uma dica do programador para a IDE/Object Inspector avisando que o programador vai iniciar sempre a propriedade com o valor informado. Assim, quando a IDE vai gravar o componente no DFM, quando ela vê que o valor de uma propriedade é o default, ela não grava o valor.


Responder

Gostei + 0

14/09/2005

Adriano Santos

[quote:67b5976be7=´Adriano Santos´]Criei um tipo enumerado e estou tentando usá-lo, mas fica sempre vazio...
você quer dizer que ele começa vazio?

Se esse for o problema, inicie a propriedade no construtor do componente...
constructor TDcDownProgress.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FOpcoes := [odCriarDestino];
end;

A palavra reservada [b:67b5976be7]default[/b:67b5976be7] tem um pegadinha... na verdade ela é uma dica do programador para a IDE/Object Inspector avisando que o programador vai iniciar sempre a propriedade com o valor informado. Assim, quando a IDE vai gravar o componente no DFM, quando ela vê que o valor de uma propriedade é o default, ela não grava o valor.[/quote:67b5976be7]

Não é isso nao, quando vou fazer o teste ela tah vazia, olha o trecho:

  if (not DirectoryExists(ExtractFilePath(FDestino))) then
  begin
    if (odCriarDestino in FOpcoes) then
      ForceDirectories(ExtractFilePath(FDestino))
    else
    begin
      MessageDlg(´O diretório destino não existe.´, mtError, [mbOk], 0);
      Exit;
    end;
  end;



[color=red:67b5976be7]Pra ser mais exato, se eu mudo a propriedade em tempo de projeto, parece que ela não é alterada, ou seja, sou obrigado a alterar em tempo de execução, tipo aqui[/color:67b5976be7]

  with DcDownProgress1 do
  begin
    Opcoes := [odCriarDestino];//mudando
    Origem := Edit1.Text;
    Destino := Edit2.Text;
    Execute;
  end;



Responder

Gostei + 0

14/09/2005

Massuda

Você mudou o construtor do seu componente conforme indiquei no meu post anterior?


Responder

Gostei + 0

14/09/2005

Adriano Santos

Você mudou o construtor do seu componente conforme indiquei no meu post anterior?


Entao Massuda, se eu fizer isso funciona...já tinha feito. O problema é quando eu mudo algo em tempo de projeto no componente. Por exemplo:

Coloco o componente no form e configuro todos os tipos para True na propriedade. Em runtime, o componente ´não sabe´ que coloquei todas como true, fica somente a que eu coloquei no constructor como verdadeira...entende?

Eu quero que funcinoe tipo a propriedade Options do DBGrid. Você vai lá desativa dgTabs e dgEdit e em runtime o componente sabe que ta desativado e não faz determinada ação....é isso...


valeu


Responder

Gostei + 0

14/09/2005

Massuda

Acho que entendi... sua propriedade não está sendo salva no DFM porque ela é um tipo de dado qu eo Delphi desconhece. Para isso acontecer, você precisa definir no seu componente como essa propriedade é lida/gravada.

Isso é feito através do método protegido DefineProperties (dê uma olhada na Ajuda do Delphi para ver um exemplo completo) combinado com um par de métodos para ler/gravar sua propriedade...
type
  TDcDownProgress = class(TComponent) 
  private 
    ...
     procedure LerOpcoes(Reader: TReader);
     procedure GravarOpcoes(Writer: TWriter);
  protected 
    procedure DefineProperties(Filer: TFiler); override;
...



Responder

Gostei + 0

14/09/2005

Adriano Santos

Acho que entendi... sua propriedade não está sendo salva no DFM porque ela é um tipo de dado qu eo Delphi desconhece. Para isso acontecer, você precisa definir no seu componente como essa propriedade é lida/gravada. Isso é feito através do método protegido DefineProperties (dê uma olhada na Ajuda do Delphi para ver um exemplo completo) combinado com um par de métodos para ler/gravar sua propriedade...
type
  TDcDownProgress = class(TComponent) 
  private 
    ...
     procedure LerOpcoes(Reader: TReader);
     procedure GravarOpcoes(Writer: TWriter);
  protected 
    procedure DefineProperties(Filer: TFiler); override;
...


Nossa Massuda, mas nunca vi isso...jurava de pe junto que ele fazia sozinho. Como o DBGrid faz? Não vi nada no fonte Grids.pas da VCL.l


Responder

Gostei + 0

14/09/2005

Massuda

[quote:15fbd375ba=´Adriano Santos´]...nunca vi isso...jurava de pe junto que ele fazia sozinho. Como o DBGrid faz? Não vi nada no fonte Grids.pas da VCL.l[/quote:15fbd375ba]Talvez (com grande chance) você tenha razão... sua propriedade é um [b:15fbd375ba]set of[/b:15fbd375ba] e o Delphi sabe lidar com isso.

Relendo o tópico percebi que você tem uma procedure TDcDownProgress.SetOptions... será que dava para você postar o código dela aqui?


Responder

Gostei + 0

15/09/2005

Adriano Santos

[quote:e095dd9793=´Adriano Santos´]...nunca vi isso...jurava de pe junto que ele fazia sozinho. Como o DBGrid faz? Não vi nada no fonte Grids.pas da VCL.l
Talvez (com grande chance) você tenha razão... sua propriedade é um [b:e095dd9793]set of[/b:e095dd9793] e o Delphi sabe lidar com isso.

Relendo o tópico percebi que você tem uma procedure TDcDownProgress.SetOptions... será que dava para você postar o código dela aqui?[/quote:e095dd9793]

Sim dá, vou colocar o fonte inteiro. Mas já mudei trocentas vezes o SetOptions.

unit DcDownProgress;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, UrlMon, ShellApi, ActiveX, ComCtrls;

type
  TOpcoesDown = (odCriarDestino, odAvisarSobrepor, odAvisarFinalizacao);
  TOpcoes = Set of TOpcoesDown;

type
  TMeuObjetoInterface = class(TInterfacedObject, IBindStatusCallback)
  private
    FProgress: TProgressBar;
    FLabelInfo: TLabel;
  public
    function OnStartBinding(dwReserved: DWORD; pib: IBinding): HResult; stdcall;
    function GetPriority(out nPriority): HResult; stdcall;
    function OnLowResource(reserved: DWORD): HResult; stdcall;
    function OnProgress(ulProgress, ulProgressMax, ulStatusCode: ULONG;
      szStatusText: LPCWSTR): HResult; stdcall;
    function OnStopBinding(hresult: HResult; szError: LPCWSTR): HResult;
      stdcall;
    function GetBindInfo(out grfBINDF: DWORD; var bindinfo: TBindInfo): HResult;
      stdcall;
    function OnDataAvailable(grfBSCF: DWORD; dwSize: DWORD; formatetc:
      PFormatEtc;
      stgmed: PStgMedium): HResult; stdcall;
    function OnObjectAvailable(const iid: TGUID; punk: IUnknown): HResult;
      stdcall;
  end;

type
  TDcDownProgress = class(TComponent)
  private
    { Private declarations }
    FProgress: TProgressBar;
    FDestino: String;
    FOrigem: String;
    FOpcoes: TOpcoes;
    FLabelInfo: TLabel;
    function GetDestino: String;
    function GetOrigem: String;
    procedure SetDestino(const Value: String);
    procedure SetOrigem(const Value: String);
    procedure SetOpcoes(const Value: TOpcoes);
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy;override;
    function Execute : Boolean;
  published
    { Published declarations }
    property Origem : String read GetOrigem write SetOrigem;
    property Destino : String read GetDestino write SetDestino;
    property ProgressBar : TProgressBar read FProgress write FProgress;
    property Opcoes : TOpcoes read FOpcoes write SetOpcoes default [odCriarDestino];
    property LabelInfo: TLabel read FLabelInfo write FLabelInfo;
  end;


procedure Register;

implementation

procedure Register;
begin
  RegisterComponents(´Doiscliques ADD´, [TDcDownProgress]);
end;

{ TDcDownProgress }

constructor TDcDownProgress.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TDcDownProgress.Destroy;
begin
  inherited;
end;

function TDcDownProgress.Execute: Boolean;
var
  MeuEstatus: TMeuObjetoInterface;
begin
  if Trim(FDestino) = ´´ then
  begin
    MessageDlg(´O destino do download não foi especificado.´, mtError, [mbOk], 0);
    Exit;
  end;
  if (not DirectoryExists(ExtractFilePath(FDestino))) then
  begin
    if (odCriarDestino in FOpcoes) then
      ForceDirectories(ExtractFilePath(FDestino))
    else
    begin
      MessageDlg(´O diretório destino não existe.´, mtError, [mbOk], 0);
      Exit;
    end;
  end;

  {Aqui inicia o Download}
  MeuEstatus := TMeuObjetoInterface.Create;
  if FProgress = nil then
  begin
    MessageDlg(´Especifique um componente ProgressBar na propriedade de mesmo nome.´,mtWarning,[mbOK],0);
    Exit;
  end;
  if FLabelInfo = nil then
  begin
    MessageDlg(´Especifique um componente Label na propriedade de mesmo nome.´,mtWarning,[mbOK],0);
    Exit;
  end;
  MeuEstatus.FProgress := FProgress;
  MeuEstatus.FLabelInfo := FLabelInfo;
  {Testa se foi configurado um ProgressBar e um Label}
  if (not (FProgress = Nil)) and (not (FLabelInfo = Nil)) then
    UrlDownloadToFile(nil, PChar(FOrigem), PChar(FDestino), 0, MeuEstatus)
  else
    UrlDownloadToFile(nil, PChar(FOrigem), PChar(FDestino), 0, nil);
  {testa se precisa dar mensagem final}
  if odAvisarFinalizacao in Opcoes then
    Messagedlg(´Download concluído´, mtInformation, [mbOk],0);
end;

function TDcDownProgress.GetDestino: String;
begin
  Result := FDestino;
end;


function TDcDownProgress.GetOrigem: String;
begin
  Result := FOrigem;
end;

procedure TDcDownProgress.SetDestino(const Value: String);
begin
  FDestino := Value;
end;

procedure TDcDownProgress.SetOpcoes(const Value: TOpcoes);
begin
  FOpcoes := Value;
end;

procedure TDcDownProgress.SetOrigem(const Value: String);
begin
  FOrigem := Value;
end;

{ TMeuObjetoInterface }

function TMeuObjetoInterface.GetBindInfo(out grfBINDF: DWORD;
  var bindinfo: TBindInfo): HResult;
begin

end;

function TMeuObjetoInterface.GetPriority(out nPriority): HResult;
begin

end;

function TMeuObjetoInterface.OnDataAvailable(grfBSCF, dwSize: DWORD;
  formatetc: PFormatEtc; stgmed: PStgMedium): HResult;
begin

end;

function TMeuObjetoInterface.OnLowResource(reserved: DWORD): HResult;
begin

end;

function TMeuObjetoInterface.OnObjectAvailable(const iid: TGUID;
  punk: IInterface): HResult;
begin

end;

function TMeuObjetoInterface.OnProgress(ulProgress, ulProgressMax,
  ulStatusCode: ULONG; szStatusText: LPCWSTR): HResult;
begin
  Application.ProcessMessages;
  if FLabelInfo <> nil then
    FLabelInfo.Caption := ´Baixando: ´ + FormatFloat(´#.,´, ulProgress)
      + ´ de ´ + FormatFloat(´.,´, ulProgressMax) + ´ total de bytes´;
  if FProgress <> nil then
  begin
    FProgress.Max := ulProgressMax;
    FProgress.Position := FProgress.Position + (ulProgress div 1024);
  end;
end;

function TMeuObjetoInterface.OnStartBinding(dwReserved: DWORD;
  pib: IBinding): HResult;
begin

end;

function TMeuObjetoInterface.OnStopBinding(hresult: HResult;
  szError: LPCWSTR): HResult;
begin

end;

end.



Responder

Gostei + 0

15/09/2005

Massuda

Não olhei seu código inteiro, aparentemente está OK, mas percebi que você não alterou o construtor TDcDownProgress.Create como mencionei num post anterior.

O fato de você por...
property Opcoes : TOpcoes read FOpcoes write SetOpcoes default [odCriarDestino];
...o [b:ac567007ac]default[/b:ac567007ac] na declaração da propriedade não inicializa a propriedade; você é que tem que fazer isso no construtor do componente.


Responder

Gostei + 0

15/09/2005

Adriano Santos

Não olhei seu código inteiro, aparentemente está OK, mas percebi que você não alterou o construtor TDcDownProgress.Create como mencionei num post anterior. O fato de você por...
property Opcoes : TOpcoes read FOpcoes write SetOpcoes default [odCriarDestino];
...o [b:48cdedcc0d]default[/b:48cdedcc0d] na declaração da propriedade não inicializa a propriedade; você é que tem que fazer isso no construtor do componente.


O default na verdade Massuda, nem precisa, coloquei por colocar. A unica coisa que quero é que o usuario do meu componente possa setar o componente em tempo de projeto e ele fazer as devidas verificações. Só isso....rs...valeu pela força.


Responder

Gostei + 0

15/09/2005

Massuda

[quote:85538cb0c1=´Adriano Santos´]O default na verdade, nem precisa, coloquei por colocar.[/quote:85538cb0c1]Então tira ele de lá, porque se você por odCriarDestino=True no Object Inspector, esse valor não é salvo pelo Delphi, pois ele deveria ser o default do seu componente.


Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar