Is it possible to clone objects in Delphi?

Asked

Viewed 5,887 times

9

It is possible to clone objects in Delphi at runtime?

For example, there is a Data Module with a zTable. If I use that zTable on two screens at the same time, with different filters, the second screen will overlay the filter used by the first.

Is it possible for me to use this zTable as a model and in onShow from my form I create a clone hers?

4 answers

6

Depending on the class, yes...

Try to create a zTable at runtime and use the command:

        zTableCriada.Assign(zTableOriginal);

Let me explain: Assign serves to get 'in theory' all the data from another component of the same class and copy it to itself, in its instance. The problem is that this is not automatic; when the programmer of the class in question is writing it (in this case, the zTable developer), he must manually program the Assign program, or else he will give an 'not implemented' error. So you’re going to run a test, because I don’t have the components installed here.

If it doesn’t work, there are several ways to do what you want. Anything I give you some ideas here.

  • If it doesn’t work, use Tclientdataset methods

  • I get it... case to procedure Assign was not programmed, I could create a Helper for my TZtable, following the same logic of the method Assign?

  • Yes. It all depends on what properties you will use. For example, to take the data, copy the SQL property and then give an Open would be enough; but you will probably want to take Displaylabel’s of the fields, home formatting, etc... Then just make a copy of everything you need. Bottom line is, overall, everything you’ll need will be focused on the Fields. Make a loop with them passing everything from one field to another would solve.

5

If the wish is simply to clone objects Delphi supports this through the Tpersistent.Assign method which is the ancestor of the Tcomponent class, which serves as the basis for the visual and non-visual components of Delphi.

This method takes the contents of an object (passed by parameter) to the new one, and would look something like this

procedure ClonazTable(zTableOriginal: TDataset);
begin
  zTableClonada.Assign(zTableOriginal);
end;

Another option is to clone objects through Rtti, traversing the object and copying the data from one to the other. There is a good article on the subject in Club Delphi magazine number 113.

However as this component is a query to the database, the information that is brought from the database will not be cloned together. To do this you need to copy the entire dataset structure to something that exists exclusively in memory, such as a Tclientdataset.

To do this, it is necessary to copy the structure first and then the data from the original Dataset to the Dataset in Memory, two of the many options that exist to facilitate this work are:

1. Tjvmemorydata: A Component of the Jedi package (which is free), it has a method that copies the structure of a Dataset to the component, leaving only the work of copying the data.

function CopiarDataSet(zTableOriginal: TDataset): TJvMemoryData;
begin
  Result := TJvMemoryData.Create(Application);
  **Result.CopyStructure(zTableOriginal);**
  zTableOriginal.First;
  while not(zTableOriginal.Eof) do
  begin
    ***//Código que copia os dados***
    zTableOriginal.Next;
  end;
end;

2. Tdxmemdata: A Component of the Developer Express package (which is paid for), it has a method that completely copies the Dataset to a new one.

function CopiarDataSet(zTableOriginal: TDataset): TdxMemData;
begin
  Result := TdxMemData.Create(Application);
  **Result.CopyFromDataSet(zTableOriginal);**
end;
  • Legal Gunar Bastos... I already use the Jedi in the system I am developing... I will try to implement the first alternative. while, where I should copy the data, I have to do so: Result.FieldByName('meu_campo').value := zTableOriginal.FieldByName('meu_campo').value ?

  • That’s right @Thiagothaison, or if you want to leave the more generic function you can iterate by zTableOriginal.Fields and use Result.FieldByName(zTableOriginal.Fields[i].FieldName).Value := zTableOriginal.Fields[i].Value;

  • Boy, it worked right! Thanks...

4

In this case it will not be possible for you to clone zTable content (assuming it is a Table component of Zeos), as it is a component whose content is recovered directly from the data server.

In his case, it would be better to have based your implementation (in fact, your entire application) on the component TClientDataset. This component does allow your content to be cloned, in order to provide the functionality you need, which is to have the same records already selected in another context, for another use, without interfering with the original component.

In your specific case, my best suggestion is to study the TClientDataset and the TDatasetProvider and thus reform your DataModule to make use of this component. Then you will add a method Clone in this DataModule that will produce the replica of it to be used at the other location without interfering with the original instance.

2


Following the tips of @Gunar Bastos I managed to find a solution to my problem. Follow below:

function CopiarDataSet(zTableOriginal: TDataset): TJvMemoryData;
var
    i:integer;
begin
    //Abrindo o dataset original
    zTableOriginal.Open;

    //Criando o clone e copiando a estrutura do original
    Result := TJvMemoryData.Create(Application);
    Result.CopyStructure(zTableOriginal);

    //Abrindo o clone
    Result.Open;

    //Movendo o cursor para o primeiro registro do dataset original
    zTableOriginal.First;

    //Iteração para copiar os dados do original para o clone
    while not(zTableOriginal.Eof) do begin

        //Preparando o clone para receber os dados
        Result.Insert;

        //Iteração sobre os campos da tabela
        for i := 0 to zTableOriginal.FieldCount - 1 do begin
                //Copiando os dados
                Result.FieldByName(zTableOriginal.Fields[i].FieldName).Value := zTableOriginal.Fields[i].Value;

                //Copiando os labels das colunas
                Result.FieldByName(zTableOriginal.Fields[i].FieldName).DisplayLabel := zTableOriginal.Fields[i].DisplayLabel;
        end;

        //Efetivando a inserção
        Result.Post;

        //Indo para o próximo registro do dataset original
        zTableOriginal.Next;
    end;

    //Fechando o dataset original
    zTableOriginal.Close;

end;

Browser other questions tagged

You are not signed in. Login or sign up in order to post.