Fórum Copiar propriedades, métodos e eventos dum objeto para outro #291816

16/08/2005

0

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]


Carlos Filho

Carlos Filho

Responder

Posts

16/08/2005

Massuda

[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.


Responder

Gostei + 0

16/08/2005

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?


Responder

Gostei + 0

16/08/2005

Carlos Filho

[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...


Responder

Gostei + 0

16/08/2005

Carlos Filho

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)


Responder

Gostei + 0

16/08/2005

Adriano Santos

[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]


Responder

Gostei + 0

16/08/2005

Massuda

[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.


Responder

Gostei + 0

16/08/2005

Carlos Filho

É... 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:


Responder

Gostei + 0

12/12/2005

Rodc

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.


Responder

Gostei + 0

13/12/2005

Rodc

[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:


Responder

Gostei + 0

04/01/2006

Rodc

[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
//---------------------------------------------------------------------------
#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.


Responder

Gostei + 0

05/01/2006

Rodc

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.


Responder

Gostei + 0

08/12/2006

Tpoeta

como eu faço pra duplicar um TPanel usando TStream.WriteComponent/TStream.ReadComponent ?


Responder

Gostei + 0

16/01/2008

Micheus

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


Responder

Gostei + 0

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

Aceitar