Usar propriedade de outra classe em componente.
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:
[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
Curtidas 0
Respostas
Massuda
14/09/2005
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.
GOSTEI 0
Adriano Santos
14/09/2005
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
GOSTEI 0
Massuda
14/09/2005
[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:
GOSTEI 0
Adriano Santos
14/09/2005
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
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;
GOSTEI 0
Massuda
14/09/2005
[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...
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.
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.
GOSTEI 0
Adriano Santos
14/09/2005
[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;
GOSTEI 0
Massuda
14/09/2005
Você mudou o construtor do seu componente conforme indiquei no meu post anterior?
GOSTEI 0
Adriano Santos
14/09/2005
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
GOSTEI 0
Massuda
14/09/2005
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...
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; ...
GOSTEI 0
Adriano Santos
14/09/2005
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
GOSTEI 0
Massuda
14/09/2005
[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?
Relendo o tópico percebi que você tem uma procedure TDcDownProgress.SetOptions... será que dava para você postar o código dela aqui?
GOSTEI 0
Adriano Santos
14/09/2005
[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.
GOSTEI 0
Massuda
14/09/2005
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......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.
O fato de você por...
property Opcoes : TOpcoes read FOpcoes write SetOpcoes default [odCriarDestino];
GOSTEI 0
Adriano Santos
14/09/2005
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......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.
property Opcoes : TOpcoes read FOpcoes write SetOpcoes default [odCriarDestino];
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.
GOSTEI 0
Massuda
14/09/2005
[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.
GOSTEI 0
Adriano Santos
14/09/2005
[quote:f316632dae=´Adriano Santos´]O default na verdade, nem precisa, coloquei por colocar.
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.[/quote:f316632dae]Ah entendi, vou testar aqui.
abraço
Obs. Vou ter que colocar créditos pra vc no artigo e no componente que estou fazendo, rs...
GOSTEI 0
Adriano Santos
14/09/2005
Ae [b:06dcd55c4b]Massuda[/b:06dcd55c4b], valeu mesmo...funcionou.
Tirei somente o default da propriedade e blz.
Vou redigir um artigo, assim que tiver pronto aviso a comunidade.
abraço
Tirei somente o default da propriedade e blz.
Vou redigir um artigo, assim que tiver pronto aviso a comunidade.
abraço
GOSTEI 0
Martins
14/09/2005
[quote:0912965d0b=´Adriano Santos´]Ae [b:0912965d0b]Massuda[/b:0912965d0b], valeu mesmo...funcionou.
Tirei somente o default da propriedade e blz.
Vou redigir um artigo, assim que tiver pronto aviso a comunidade.
abraço[/quote:0912965d0b]
Manda ver, põe logo esse artigo no ar!!!!
Boa Sorte [b:0912965d0b]Adriano[/b:0912965d0b]
Tirei somente o default da propriedade e blz.
Vou redigir um artigo, assim que tiver pronto aviso a comunidade.
abraço[/quote:0912965d0b]
Manda ver, põe logo esse artigo no ar!!!!
Boa Sorte [b:0912965d0b]Adriano[/b:0912965d0b]
GOSTEI 0