Copiar propriedades, métodos e eventos dum objeto para outro
Gostaria de saber como copio de uma só vez todas as propriedades, métodos e eventos de um objeto para outro, tipo,
se eu tenho um botão com algumas propriedades configuradas e um evento de clique, eu crio um outro botão em tempo de execução e quero que esse novo botão faça exatamente o mesmo que o primeiro, uma cópia.
Eu conheço o método Assign, mas não consigo usar pq simplesmente ele não funciona, tipo
Button2.Assign(Button1);
Dá erro dizendo que Não é possivel atribuir um TButton a um TButton!
Alguem pode me explicar?
[color=green:0c7d85de66]Título editado por gandalf.nho. Procure usar títulos mais explicativos (´Dúvida avançada...´)[/color:0c7d85de66]
se eu tenho um botão com algumas propriedades configuradas e um evento de clique, eu crio um outro botão em tempo de execução e quero que esse novo botão faça exatamente o mesmo que o primeiro, uma cópia.
Eu conheço o método Assign, mas não consigo usar pq simplesmente ele não funciona, tipo
Button2.Assign(Button1);
Dá erro dizendo que Não é possivel atribuir um TButton a um TButton!
Alguem pode me explicar?
[color=green:0c7d85de66]Título editado por gandalf.nho. Procure usar títulos mais explicativos (´Dúvida avançada...´)[/color:0c7d85de66]
Carlos Filho
Curtidas 0
Respostas
Massuda
16/08/2005
[quote:129e9749d2=´derek wildstar´]Dá erro dizendo que Não é possivel atribuir um TButton a um TButton![/quote:129e9749d2]Problema curioso... pelo que pesquisei, dentro da VCL nenhuma classe derivada de TComponent (como é o caso de TButton) implementa o método Assign. Provavelmente uma decisão de projeto, mas precisaria pesquisar mais para entender a motivação.
No seu caso, você pode copiar uma a uma as propriedades de um botão para outro. Tem outra alternativa mais sofisticada, baseada em streams.
No seu caso, você pode copiar uma a uma as propriedades de um botão para outro. Tem outra alternativa mais sofisticada, baseada em streams.
GOSTEI 0
Adriano Santos
16/08/2005
Só um parenteses amigo, não leva a mal.
Coloque um título mais explicativo nos seus posts, fica mais fácil pra todos, ok?
Coloque um título mais explicativo nos seus posts, fica mais fácil pra todos, ok?
GOSTEI 0
Carlos Filho
16/08/2005
[quote:82b30fa074=´Adriano Santos´]Só um parenteses amigo, não leva a mal.
Coloque um título mais explicativo nos seus posts, fica mais fácil pra todos, ok?[/quote:82b30fa074]
Eu até pensei em por, mas (acho que estou errado) uma vez fiz isso e levei a mesma bronca dizendo que não se deve por perguntas no titulo.
Mas acho que deve ter sido em outro forum...
Coloque um título mais explicativo nos seus posts, fica mais fácil pra todos, ok?[/quote:82b30fa074]
Eu até pensei em por, mas (acho que estou errado) uma vez fiz isso e levei a mesma bronca dizendo que não se deve por perguntas no titulo.
Mas acho que deve ter sido em outro forum...
GOSTEI 0
Carlos Filho
16/08/2005
No seu caso, você pode copiar uma a uma as propriedades de um botão para outro. Tem outra alternativa mais sofisticada, baseada em streams.
É exatamente isso que eu to fazendo agora, mas como eu pretendo criar uma função genérica, seria mais interessante criar um objeto temporário e copiar as propriedades e eventos de uma só vez...
Como seria usando Streams? Funciona mesmo ou tem limitações? (que só seriam resolvidas se o Assign funcionasse bem)
GOSTEI 0
Adriano Santos
16/08/2005
[quote:8f062edce9=´derek wildstar´][quote:8f062edce9=´Adriano Santos´]Só um parenteses amigo, não leva a mal.
Coloque um título mais explicativo nos seus posts, fica mais fácil pra todos, ok?[/quote:8f062edce9]
Eu até pensei em por, mas (acho que estou errado) uma vez fiz isso e levei a mesma bronca dizendo que não se deve por perguntas no titulo.
Mas acho que deve ter sido em outro forum...[/quote:8f062edce9]
Tranquilo véio, não é bronca não. É que tem usuário que não entra mesmo no tópico se o título não estiver muito explicado...eu mesmo sou um deles, entrei por curisoso neste...rsss...se preferir dá uma olhada nas regras de conduta deste fórum, aki é todo mundo camarada pode comprovar.
[url=http://forum.clubedelphi.net/viewtopic.php?t=6689]Regras de conduta[/url]
Coloque um título mais explicativo nos seus posts, fica mais fácil pra todos, ok?[/quote:8f062edce9]
Eu até pensei em por, mas (acho que estou errado) uma vez fiz isso e levei a mesma bronca dizendo que não se deve por perguntas no titulo.
Mas acho que deve ter sido em outro forum...[/quote:8f062edce9]
Tranquilo véio, não é bronca não. É que tem usuário que não entra mesmo no tópico se o título não estiver muito explicado...eu mesmo sou um deles, entrei por curisoso neste...rsss...se preferir dá uma olhada nas regras de conduta deste fórum, aki é todo mundo camarada pode comprovar.
[url=http://forum.clubedelphi.net/viewtopic.php?t=6689]Regras de conduta[/url]
GOSTEI 0
Massuda
16/08/2005
[quote:af64e00e71=´derek wildstar´]Como seria usando Streams? Funciona mesmo ou tem limitações?[/quote:af64e00e71]Achava que dava para usar TStream.WriteComponent/TStream.ReadComponent para poder clonar um TComponent, mas testei e descobri que não funciona como esperado; por exemplo, os eventos não são clonados. Portanto, usar stream não resolve o problema.
GOSTEI 0
Carlos Filho
16/08/2005
É... vou mesmo ter de criar um componente...
Minha idéia era simplesmente aplicar propriedades em um TEdit por exemplo a fim de tornar seu texto centralizado.
O que eu tava fazendo era type casts de um TEdit para um TAlignEdit (q eu criei) e aplicava as propriedadas recriando o componente, mas para isso eu tinha de antes copiar as propriedades que seriam perdidas com o Free.
Minha dúvida principal nesse tópico seria portanto PORQUE O ASSING NUNCA FUNCIONA QUANDO A GENTE PRECISA DELE??
Sobre as regras do forum eu tenho de admintir que nunca li! :oops: Mas não sou novato! heehhe é desleixo mesmo! :wink:
Minha idéia era simplesmente aplicar propriedades em um TEdit por exemplo a fim de tornar seu texto centralizado.
O que eu tava fazendo era type casts de um TEdit para um TAlignEdit (q eu criei) e aplicava as propriedadas recriando o componente, mas para isso eu tinha de antes copiar as propriedades que seriam perdidas com o Free.
Minha dúvida principal nesse tópico seria portanto PORQUE O ASSING NUNCA FUNCIONA QUANDO A GENTE PRECISA DELE??
Sobre as regras do forum eu tenho de admintir que nunca li! :oops: Mas não sou novato! heehhe é desleixo mesmo! :wink:
GOSTEI 0
Rodc
16/08/2005
Olá, você conseguiu fazer a duplicação do componente? Estou precisando duplicar um TPanel com todos os componentes que tiver dentro dele (TButton, TLabel, etc...). E claro, sem perder o link dos eventos deles.
GOSTEI 0
Rodc
16/08/2005
[quote:2f156d3bf8=´derek wildstar´]Dá erro dizendo que Não é possivel atribuir um TButton a um TButton! Problema curioso... pelo que pesquisei, dentro da VCL nenhuma classe derivada de TComponent (como é o caso de TButton) implementa o método Assign.[/quote:2f156d3bf8]
É verdade o metodo Assign do TPersistent apenas chama o método AssignError, que mostra o erro descrito. Não tem código nenhum lá fazendo a duplicação do componente. Que estranho!!! :shock:
É verdade o metodo Assign do TPersistent apenas chama o método AssignError, que mostra o erro descrito. Não tem código nenhum lá fazendo a duplicação do componente. Que estranho!!! :shock:
GOSTEI 0
Rodc
16/08/2005
[color=red:3f7839af21]Finalmente consegui!!!!![/color:3f7839af21]
Depois de muito pesquisar no google, depois de muito tentar entender Inglês e depois de muitos testes, consegui resolver o problema da cópia de componentes. Para que outros também não tenham que se matar de pesquisar... vou disponibilizar o código.
O código foi pego do site de um dos programadores da Borland (http://www.blong.com) mas uma unit do BCB tá com erro. Depois de muito pesquisar encontrei a solução e corrigi o código do cara.
Unit RTTIUnit.cpp
Cabeçalho da unit RTTIUnit.h
a unit TypInfo.hpp ($(BCB)\Source\vcl) tem que ser modificada pois está em conflito com a System.hpp.
Troque
por
e troque
por
No meu caso vou implementar ainda para a função copiar todos os componentes childrens do componente passado por referencia. Ex. Copiar todos os edits e Labels que estiverem dentro de um TPanel.
Depois de muito pesquisar no google, depois de muito tentar entender Inglês e depois de muitos testes, consegui resolver o problema da cópia de componentes. Para que outros também não tenham que se matar de pesquisar... vou disponibilizar o código.
O código foi pego do site de um dos programadores da Borland (http://www.blong.com) mas uma unit do BCB tá com erro. Depois de muito pesquisar encontrei a solução e corrigi o código do cara.
Unit RTTIUnit.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
pragma hdrstop
include "RTTIUnit.h"
include <TypInfo.hpp>
include <Registry.hpp>
include <alloc.h>
const NoDefault = 0x80000000;
//V3 TTypeKind ends in tkInterface
//V4 TTypeKind ends in tkDynArray
#if __BCPLUSPLUS__ < 0x540
define tkPropsWithDefault (System::Set<Typinfo::TTypeKind, tkUnknown, tkInterface> () \
<< tkInteger << tkChar << tkEnumeration << tkSet )
else
define tkPropsWithDefault (System::Set<Typinfo::TTypeKind, tkUnknown, tkDynArray> () \
<< tkInteger << tkChar << tkEnumeration << tkSet )
endif
void SetDefaults(TObject *Obj)
{
//Find out how many properties we´ll be considering
int Count = GetPropList((PTypeInfo)(Obj->ClassInfo()), tkPropsWithDefault, NULL);
//Allocate memory to hold their RTTI data
PPropList List = (PPropList) new PPropInfo[Count];
try
{
//Get hold of the property list in our new buffer
GetPropList((PTypeInfo)(Obj->ClassInfo()), tkPropsWithDefault, List);
//Loop through all the selected properties
for (int i = 0; i < Count; i++)
#if __BCPLUSPLUS__ > 0x540
//If there is supposed to be a default value...
if ((*List[i])->Default != NoDefault)
//...then jolly well set it
SetOrdProp(Obj, *List[i], (*List[i])->Default);
else
//If there is supposed to be a default value...
if (List[i]->Default != NoDefault)
//...then jolly well set it
SetOrdProp(Obj, List[i], List[i]->Default);
endif
}
__finally
{
delete[] List;
}
}
void CopyObject(TObject *ObjFrom, TObject *ObjTo)
{
//Iterate thru all published fields and
//properties of source copying them to target
//Find out how many properties we´ll be considering
int Count = GetPropList((PTypeInfo)(ObjFrom->ClassInfo()), tkAny, NULL);
//Allocate memory to hold their RTTI data
PPropList PropInfos = (PPropList) new PPropInfo[Count];
try
{
//Get hold of the property list in our new buffer
GetPropList((PTypeInfo)(ObjFrom->ClassInfo()), tkAny, PropInfos);
//Loop through all the selected properties
for (int i = 0; i < Count; i++)
{
PPropInfo PropInfo = GetPropInfo((PTypeInfo)ObjTo->ClassInfo(), (*PropInfos)[i]->Name);
//Check the general type of the property
//and read/write it in an appropriate way
switch ((*(*PropInfos)[i]->PropType)->Kind)
{
case tkClass:
{
//Ignore properties which are themselves objects
break;
}
case tkInteger:;
case tkChar:;
case tkEnumeration:;
case tkSet:;
case tkWChar:
{
int OrdVal = GetOrdProp(ObjFrom, (*PropInfos)[i]);
if (PropInfo)
SetOrdProp(ObjTo, PropInfo, OrdVal);
break;
}
case tkFloat:
{
double FloatVal = GetFloatProp(ObjFrom, (*PropInfos)[i]);
if (PropInfo)
SetFloatProp(ObjTo, PropInfo, FloatVal);
break;
}
case tkWString:;
case tkLString:;
case tkString:
{
//Avoid copying "Name" - components must have unique names
if (UpperCase((*PropInfos)[i]->Name) != "NAME")
{
String StrVal = GetStrProp(ObjFrom, (*PropInfos)[i]);
if (PropInfo)
SetStrProp(ObjTo, PropInfo, StrVal);
}
break;
}
case tkMethod:
{
TMethod MethodVal = GetMethodProp(ObjFrom, (*PropInfos)[i]);
if (PropInfo)
SetMethodProp(ObjTo, PropInfo, MethodVal);
}
}
}
}
__finally
{
delete[] PropInfos;
}
}
TRegIniFile *Reg;
const String Section = "Property Values";
//---------------------------------------------------------------------------
void ReadProp(TObject *Obj, const String PropName)
{
PPropInfo Prop =
GetPropInfo((PTypeInfo)Obj->ClassInfo(), PropName);
if (!Prop)
throw Exception("Property ¬s not found in ¬s class",
ARRAYOFCONST((PropName, Obj->ClassName())));
//For each case, read a value from the registry, using
//the current value as the default, then use that read
//value to set the property
switch ((*Prop->PropType)->Kind)
{
case tkWString:;
case tkLString:;
case tkString:
SetStrProp(Obj, Prop,
Reg->ReadString(Section, PropName, GetStrProp(Obj, Prop)));
break;
case tkInteger:;
case tkChar:;
case tkSet:;
case tkWChar:;
SetOrdProp(Obj, Prop,
Reg->ReadInteger(Section, PropName, GetOrdProp(Obj, Prop)));
break;
case tkFloat:
SetFloatProp(Obj, Prop, StrToFloat(
Reg->ReadString(Section, PropName,
FloatToStr(GetFloatProp(Obj, Prop)))));
break;
//Enums are written out as strings
case tkEnumeration:
SetOrdProp(Obj, Prop, GetEnumValue(
*Prop->PropType, Reg->ReadString(Section, PropName,
GetEnumName(*Prop->PropType, GetOrdProp(Obj, Prop)))));
}
}
void ReadProps(TObject *Obj, const String *PropNames, const int PropNames_Size)
{
for (int i = 0; i <= PropNames_Size; i++)
ReadProp(Obj, PropNames[i]);
}
void WriteProp(TObject *Obj, const String PropName)
{
PPropInfo Prop =
GetPropInfo((PTypeInfo)Obj->ClassInfo(), PropName);
if (!Prop)
throw Exception("Property ¬s not found in ¬s class",
ARRAYOFCONST((PropName, Obj->ClassName())));
//For each case, write the property value to the registry
switch ((*Prop->PropType)->Kind)
{
case tkWString:;
case tkLString:;
case tkString:
Reg->WriteString(Section, PropName, GetStrProp(Obj, Prop));
break;
case tkInteger:;
case tkChar:;
case tkSet:;
case tkWChar:;
Reg->WriteInteger(Section, PropName, GetOrdProp(Obj, Prop));
break;
case tkFloat:
Reg->WriteString(Section, PropName, FloatToStr(GetFloatProp(Obj, Prop)));
break;
//Enums are written out as strings
case tkEnumeration:
Reg->WriteString(Section, PropName,
GetEnumName(*Prop->PropType, GetOrdProp(Obj, Prop)));
}
}
void WriteProps(TObject *Obj, const String *PropNames, const int PropNames_Size)
{
for (int i = 0; i <= PropNames_Size; i++)
WriteProp(Obj, PropNames[i]);
}
void Initialization(void)
{
Reg = new TRegIniFile("Software\\BLong\\Property Saver");
}
pragma startup Initialization
void Finalization(void)
{
delete Reg;
}
pragma exit Finalization
pragma package(smart_init)Cabeçalho da unit RTTIUnit.h
//--------------------------------------------------------------------------- #ifndef RTTIUnitH define RTTIUnitH include <vcl.h> pragma hdrstop //--------------------------------------------------------------------------- void SetDefaults(TObject *Obj); void CopyObject(TObject *ObjFrom, TObject *ObjTo); void ReadProp(TObject *Obj, const String PropName); void ReadProps(TObject *Obj, const String *PropNames, const int PropNames_Size); void WriteProp(TObject *Obj, const String PropName); void WriteProps(TObject *Obj, const String *PropNames, const int PropNames_Size); //--------------------------------------------------------------------------- endif
a unit TypInfo.hpp ($(BCB)\Source\vcl) tem que ser modificada pois está em conflito com a System.hpp.
Troque
typedef PPropInfo *PPropList;
por
typedef TPropList *PPropList;
e troque
#define tkAny (System::Set<TTypeKind, tkUnknown, tkDynArray> () << TTypeKind(0) << TTypeKind(1) << TTypeKind(2) << TTypeKind(3) << TTypeKind(4) << TTypeKind(5) << TTypeKind(6) << TTypeKind(7) << TTypeKind(8) << TTypeKind(9) << TTypeKind(10) << TTypeKind(11) << TTypeKind(12) << TTypeKind(13) << TTypeKind(14) << TTypeKind(15) << TTypeKind(16) << TTypeKind(17) ) define tkMethods (System::Set<TTypeKind, tkUnknown, tkDynArray> () << TTypeKind(8) ) define tkProperties (System::Set<TTypeKind, tkUnknown, tkDynArray> () << TTypeKind(1) << TTypeKind(2) << TTypeKind(3) << TTypeKind(4) << TTypeKind(5) << TTypeKind(6) << TTypeKind(7) << TTypeKind(9) << TTypeKind(10) << TTypeKind(11) << TTypeKind(12) << TTypeKind(13) << TTypeKind(14) << TTypeKind(15) << TTypeKind(16) << TTypeKind(17) )
por
#define tkAny (System::Set<Typinfo::TTypeKind, tkUnknown, tkDynArray> () << Typinfo::TTypeKind(0) << Typinfo::TTypeKind(1) << Typinfo::TTypeKind(2) << Typinfo::TTypeKind(3) << Typinfo::TTypeKind(4) << Typinfo::TTypeKind(5) << Typinfo::TTypeKind(6) << Typinfo::TTypeKind(7) << Typinfo::TTypeKind(8) << Typinfo::TTypeKind(9) << Typinfo::TTypeKind(10) << Typinfo::TTypeKind(11) << Typinfo::TTypeKind(12) << Typinfo::TTypeKind(13) << Typinfo::TTypeKind(14) << Typinfo::TTypeKind(15) << Typinfo::TTypeKind(16) << Typinfo::TTypeKind(17) ) define tkMethods (System::Set<Typinfo::TTypeKind, tkUnknown, tkDynArray> () << Typinfo::TTypeKind(8) ) define tkProperties (System::Set<Typinfo::TTypeKind, tkUnknown, tkDynArray> () << Typinfo::TTypeKind(1) << Typinfo::TTypeKind(2) << Typinfo::TTypeKind(3) << Typinfo::TTypeKind(4) << Typinfo::TTypeKind(5) << Typinfo::TTypeKind(6) << Typinfo::TTypeKind(7) << Typinfo::TTypeKind(9) << Typinfo::TTypeKind(10) << Typinfo::TTypeKind(11) << Typinfo::TTypeKind(12) << Typinfo::TTypeKind(13) << Typinfo::TTypeKind(14) << Typinfo::TTypeKind(15) << Typinfo::TTypeKind(16) << Typinfo::TTypeKind(17) )
No meu caso vou implementar ainda para a função copiar todos os componentes childrens do componente passado por referencia. Ex. Copiar todos os edits e Labels que estiverem dentro de um TPanel.
GOSTEI 0
Rodc
16/08/2005
Hehehe! Foi mal, esqueci o forum era de Delphi e não de C++. Se alguém puder converter este código para Delphi e disponibilizar aqui seria legal.
GOSTEI 0
Tpoeta
16/08/2005
como eu faço pra duplicar um TPanel usando TStream.WriteComponent/TStream.ReadComponent ?
GOSTEI 0
Micheus
16/08/2005
Hehehe! Foi mal, esqueci o forum era de Delphi e não de C++. Se alguém puder converter este código para Delphi e disponibilizar aqui seria legal.
Como este tópico foi referenciado em outro forum (DevMedia), e não havia sido apresentada uma solução aqui, segue o [url=http://www.activedelphi.com.br/forum/viewtopic.php?p=208641&highlight=#208641]link[/url] com uma proposta de procedure para clonagem de componentes em run-time.
Abraços
GOSTEI 0