C ++ Builder XE4, 10.2 Токио> TStreamWriter> clWhite не может быть скопировано - PullRequest
0 голосов
/ 26 декабря 2018

Моя среда:

  • RadStudio 10.2 Токио (и также XE4)

Я реализовывал метод свойства копирования для копирования свойств TShape.

Вот что я реализовал:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    // set Shape1 color to [clWhite]
    Shape1->Brush->Color = clRed;   // clWhite
    Shape2->Brush->Color = clAqua;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::copyProperties(TControl *srcCtrl, TControl *dstCtrl)
{
    // to Keep original names
    String orgName_src = srcCtrl->Name;
    String orgName_dst = dstCtrl->Name;

    // copy properties
    TMemoryStream *strm = new TMemoryStream;
    Shape1->Name = L"";  // to avoid source collision
    try {
        strm->WriteComponent(srcCtrl);
        strm->Position = 0;
        strm->ReadComponent(dstCtrl);
    }
    __finally
    {
        delete strm;
    }

    srcCtrl->Name = orgName_src;
    dstCtrl->Name = orgName_dst;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    copyProperties((TControl *)Shape1, (TControl *)Shape2);

    // shift to avoid position-overlapping
    Shape2->Left = Shape1->Left + 150;
}
//---------------------------------------------------------------------------

Код работает нормально.

Но есть один случай, когда код не работает.т.е. когда Brush-> Color = clWhite для Shape1.

Это ошибка?можно воспроизвести и для XE4.

Интересно, почему только в clWhite есть такая ошибка?Другие цвета не имеют такого рода ошибки.

1 Ответ

0 голосов
/ 28 декабря 2018

В потоке нет ошибок.Он работает как задумано.Вы просто используете его способом, для которого он не предназначен.

clWhite является объявленным значением default свойства TBrush.Color.Система потоковой передачи DFM не выполняет потоковую передачу свойств, для которых в настоящее время установлены значения по умолчанию, если только эти свойства не объявлены как nodefault или stored=true.TBrush.Color не является ни тем, ни другим.Таким образом, текущее значение Brush.Color не будет передаваться в потоковом режиме, если оно установлено на clWhite.

Попробуйте использовать систему RTTI напрямую, а не систему DFM для копирования свойств из одного объекта в другой.Затем вы можете скопировать значения свойств независимо от значений по умолчанию, если вы решите это сделать.И вы можете игнорировать свойство Name, не сохраняя его каждый раз.

Например:

#include <System.TypInfo.hpp>

void __fastcall TForm1::copyProperties(TControl *srcCtrl, TControl *dstCtrl)
{
    PTypeInfo pDstTypeInfo = static_cast<PTypeInfo>(dstCtrl->ClassInfo());

    PPropList srcPropList;
    int srcPropCount = GetPropList(srcCtrl, srcPropList);
    try
    {
        for (int i = 0; i < srcPropCount; ++i)
        {
            PPropInfo pSrcPropInfo = (*srcPropList)[i];
            if (pSrcPropInfo->Name == "Name") continue;

            PTypeInfo pSrcPropTypeInfo = *(pSrcPropInfo->PropType);

            if (pSrcPropTypeInfo->Kind == tkClass)
            {
                PPropInfo pDstPropInfo = GetPropInfo(pDstTypeInfo, pSrcPropInfo->Name, TTypeKinds() << tkClass);
                if (pDstPropInfo)
                {
                    TPersistent *pDstObj = static_cast<TPersistent*>(GetObjectProp(dstCtrl, pDstPropInfo, __classid(TPersistent)));
                    if (pDstObj)
                    {
                        TPersistent *pSrcObj = static_cast<TPersistent*>(GetObjectProp(srcCtrl, pSrcPropInfo, __classid(TPersistent)));
                        pDstObj->Assign(pSrcObj);
                    }
                }
            }
            else
            {
                PPropInfo pDstPropInfo = GetPropInfo(pDstTypeInfo, pSrcPropInfo->Name);
                if (pDstPropInfo)
                {
                    Variant value = GetPropValue(srcCtrl, pSrcPropInfo);
                    SetPropValue(dstCtrl, pDstPropInfo, value);
                }
            }
        }
    }
    __finally
    {
        FreeMem(srcPropList);
    }
}

В качестве альтернативы:

#include <System.Rtti.hpp>

void __fastcall TForm1::copyProperties(TControl *srcCtrl, TControl *dstCtrl)
{
    TRttiContext ctx;

    TRttiType *pSrcType = ctx.GetType(srcCtrl->ClassInfo());
    TRttiType *pDstType = ctx.GetType(dstCtrl->ClassInfo());

    DynamicArray<TRttiProperty*> srcProps = pSrcType->GetProperties();
    for (int i = 0; i < srcProps.Length; ++i)
    {
        TRttiProperty *pSrcProp = srcProps[i];
        if (pSrcProp->Name == L"Name") continue;

        if (pSrcProp->PropertyType->TypeKind == tkClass)
        {
            TRttiProperty *pDstProp = pDstType->GetProperty(pSrcPropInfo->Name);
            if ((pDstProp) && (pDstProp->PropertyType->TypeKind == tkClass))
            {
                TPersistent *pDstObj = dynamic_cast<TPersistent*>(pDstProp->GetValue(dstCtrl).AsObject());
                if (pDstObj)
                {
                    TPersistent *pSrcObj = dynamic_cast<TPersistent*>(pSrcProp->GetValue(srcCtrl).AsObject());
                    pDstObj->Assign(pSrcObj);
                }
            }
        }
        else
        {
            TRttiProperty *pDstProp = pDstType->GetProperty(pSrcPropInfo->Name);
            if (pDstProp)
            {
                TValue value = pSrcProp->GetValue(srcCtrl);
                pDstProp->SetValue(dstCtrl, value);
            }
        }
    }
}
...