propertiesc++buildercustom-componentc++builder-xe

C++ Builder XE - publishing array property


I am writing my custom visual component and find it convenient to publish some of its properties as array:

class PACKAGE TVctDiag2 : public TCustomControl
{
__published:
    __property int ArrowStyle[int index] = {read=GetArrowStyle,write=SetArrowStyle};
protected:
    void __fastcall SetArrowStyle(int index, int value);
    int __fastcall GetArrowStyle(int index);
...
};

Component is built and installed without problems. But after I try to insert component on form, access violation message box shows. When debugging source of error I found, that method GetArrowStyle is called with index value of -1 which causes reading out of array bounds. I understand that user of TVctDiag2 class (=integrated development environment) cannot know what is the array size. The size of array is constant and its quite a small number (6), so alternative solution would be:

class PACKAGE TVctDiag2 : public TCustomControl
{
__published:
    __property int ArrowStyle1 = {read=GetArrowStyle1,write=SetArrowStyle1};
    __property int ArrowStyle2 = {read=GetArrowStyle2,write=SetArrowStyle2};
    __property int ArrowStyle3 = {read=GetArrowStyle3,write=SetArrowStyle3};
    __property int ArrowStyle4 = {read=GetArrowStyle4,write=SetArrowStyle4};
    __property int ArrowStyle5 = {read=GetArrowStyle5,write=SetArrowStyle5};
    __property int ArrowStyle6 = {read=GetArrowStyle6,write=SetArrowStyle6};
protected:
    void __fastcall SetArrowStyle1(int index, int value);
    int __fastcall GetArrowStyle1(int index);
    void __fastcall SetArrowStyle2(int index, int value);
    int __fastcall GetArrowStyle2(int index);
    void __fastcall SetArrowStyle3(int index, int value);
    int __fastcall GetArrowStyle3(int index);
    void __fastcall SetArrowStyle4(int index, int value);
    int __fastcall GetArrowStyle4(int index);
    void __fastcall SetArrowStyle5(int index, int value);
    int __fastcall GetArrowStyle5(int index);
    void __fastcall SetArrowStyle6(int index, int value);
    int __fastcall GetArrowStyle6(int index);
...
};

But I prefer more general solution. How can this be accomplished, if possible with option to change property values through Object inspector.


Solution

  • Declare array properties as public instead. __published is used for design-time editing and RTTI generation, which do not support array properties:

    class PACKAGE TVctDiag2 : public TCustomControl
    {
    public:
        __property int ArrowStyle[int index] = {read=GetArrowStyle,write=SetArrowStyle};
    protected:
        void __fastcall SetArrowStyle(int index, int value);
        int __fastcall GetArrowStyle(int index);
    ...
    };
    

    Your second example is buggy. You need to remove the index parameters from the getter/setter methods since the properties does not use indexes (by using non-array properties, you can declare them as __published):

    class PACKAGE TVctDiag2 : public TCustomControl
    {
    __published:
        __property int ArrowStyle1 = {read=GetArrowStyle1,write=SetArrowStyle1};
        __property int ArrowStyle2 = {read=GetArrowStyle2,write=SetArrowStyle2};
        __property int ArrowStyle3 = {read=GetArrowStyle3,write=SetArrowStyle3};
        __property int ArrowStyle4 = {read=GetArrowStyle4,write=SetArrowStyle4};
        __property int ArrowStyle5 = {read=GetArrowStyle5,write=SetArrowStyle5};
        __property int ArrowStyle6 = {read=GetArrowStyle6,write=SetArrowStyle6};
    protected:
        void __fastcall SetArrowStyle1(int value);
        int __fastcall GetArrowStyle1();
        void __fastcall SetArrowStyle2(int value);
        int __fastcall GetArrowStyle2();
        void __fastcall SetArrowStyle3(int value);
        int __fastcall GetArrowStyle3();
        void __fastcall SetArrowStyle4(int value);
        int __fastcall GetArrowStyle4();
        void __fastcall SetArrowStyle5(int value);
        int __fastcall GetArrowStyle5();
        void __fastcall SetArrowStyle6(int value);
        int __fastcall GetArrowStyle6();
    ...
    };
    

    If you want to use separate properties for the individual array values, I would suggest going back to using indexes with a single set of getter/setter methods by using the index specifier on the property declarations (I would even go as far as declaring a public array property again for good measure, in case you ever need to loop through the values in code):

    class PACKAGE TVctDiag2 : public TCustomControl
    {
    __published:
        __property int ArrowStyle1 = {read=GetArrowStyle,write=SetArrowStyle,index=0};
        __property int ArrowStyle2 = {read=GetArrowStyle,write=SetArrowStyle,index=1};
        __property int ArrowStyle3 = {read=GetArrowStyle,write=SetArrowStyle,index=2};
        __property int ArrowStyle4 = {read=GetArrowStyle,write=SetArrowStyle,index=3};
        __property int ArrowStyle5 = {read=GetArrowStyle,write=SetArrowStyle,index=4};
        __property int ArrowStyle6 = {read=GetArrowStyle,write=SetArrowStyle,index=5};
    public:
        __property int ArrowStyle[int index] = {read=GetArrowStyle,write=SetArrowStyle};
    protected:
        void __fastcall SetArrowStyle(int index, int value);
        int __fastcall GetArrowStyle(int index);
    ...
    };
    

    If you want design-time editing of an array, you either need to write a custom component editor and register it with the IDE, or re-write the array property into a TCollection (which is fully supported in RTTI and design-time editing).