Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Properties of TImage not available in the IDE when embedded


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 2 - Last Post: Feb 12, 2016 4:28 AM Last Post By: James Williams
James Williams

Posts: 63
Registered: 8/22/13
Properties of TImage not available in the IDE when embedded  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 11, 2016 6:35 AM
Hello,

I have created an arbitrary panel component that inherits from TCustPanel. In this component I embedded a TImage. Additionally, I created a auxilary class,TmyPropertyGroup, that inherits from TPersistent that provides a "Grouping" of custom properties for my new TmyPanel component. TmyPanel creates an instance of TmyPropertyGroup. Likewise, TmyPropertyGroup includes instances of TImage objects for use by the main TmyPanel. TmyPropertyGroup exposes a read only published property of the TImage pointers such that images can be loaded during design time. TmyPanel exposes a pointer to TmyPropertyGroup in the published section so that all the custom properties can be accessed. The problem is that the properties that are TImage do not expose any of the underlying properties, events in the property inspect at design time. I have no access to it at all. Is there another approach that I should be using to group embedded components such that their properties are accessible by the main component in the property inspect at design time?

What I am trying to do is use two images that are stored in the TmyPropertyGroup which is used to set the "Picture" of the FImageState in the TmyPanel. This is done by the use of another property called ImageState which is a bool type. If ImageState is true, then the displayed image on the panel receives the FmyProperties->ActiveImage->Picture, whereas if ImageState is false, then FImageState->Picture = FmyProperties->InactiveImage->Picture.

All images are created in the constructor of each of the two classes and the pointers are valid. The problem is, I get no access to any of the TImage in the property inspector within the IDE.

See a stripped down example of what I am trying to do.

class PACKAGE TmyPropertyGroup : public TPersistent
{
private:
  TComponent * FOwner;
  TImage * FInactiveImage;
  TImage * FActiveImage;
  void __fastcall SetInactiveImage(TImage * ADummy);
  void __fastcall SetActiveImage(TImage * ADummy);
 
public:
  __fastcall TmyPropertyGroup(TComponent FOwner);
  __fastcall ~TmyPropertyGroup(void);
__published:
  __property TImage * InactiveImage={read=FInactiveImage,write=SetInactiveImage};
  __property TImage * ActiveImage={read=FActiveImage,write=SetActiveImage};
 
};
 
class PACKAGE TmyPanel : public TCustomPanel
{
private:
  TmyPropertyGroup * FmyProperties;
  TImage * FIndicatorImage;
  
  bool FImageState;
 
 
  void __fastcall SetMyPropertiers(TmyPropertyGroup * ADummy);
  void __fastcall SetImageState(bool AState);
 
public:
  __fastcall TmyPanel(TComponent * AOwner);
  __fastcall ~TmyPanel(void);
 
__published:
  __property TmyPropertyGroup * Properties={read=FmyProperties,write=SetMyProperties};
  __property bool ImageState={read=FImageState,write=SetImageState};  
 
};
 


Edited by: James Williams on Feb 11, 2016 7:25 AM
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Properties of TImage not available in the IDE when embedded [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 11, 2016 1:44 PM   in response to: James Williams in response to: James Williams
James wrote:

The problem is that the properties that are TImage do not expose
any of the underlying properties, events in the property inspect at
design time.

Are you calling SetSubComponent(True) on them when creating them?

I have no access to it at all. Is there another approach that I should
be using to group embedded components such that their properties are
accessible by the main component in the property inspect at design time?

Why are you using TImage at all, and not TPicture instead? TImage is a visual
component, it should not be used for backing properties. TPicture should
be used instead. At runtime, your panel component can Assign() the appropriate
TPicture data to its internal TImage object for display purposes.

What I am trying to do is use two images that are stored in the TmyPropertyGroup
which is used to set the "Picture" of the FImageState in the TmyPanel.

This is done by the use of another property called ImageState which is a
bool type. If ImageState is true, then the displayed image on the panel
receives the FmyProperties->ActiveImage->Picture, whereas if ImageState
is false, then FImageState->Picture = FmyProperties->InactiveImage->Picture.

See, you are already using TPicture anyway, so you don't actually need TImage
at all, and should remove it, just use TPicture by itself.

Try something more like this:

class PACKAGE TmyPropertyGroup : public TPersistent
{
private:
    TPicture *FActiveImage;
    TPicture *FInactiveImage;
    TNotifyEvent FOnActiveImageChange;
    TNotifyEvent FOnInactiveImageChange;
 
    void __fastcall ActiveImageChanged(TObject *Sender);
    void __fastcall InactiveImageChanged(TObject *Sender);
    void __fastcall SetActiveImage(TPicture *Value);
    void __fastcall SetInactiveImage(TPicture *Value);
 
public:
    __fastcall TmyPropertyGroup();
    __fastcall ~TmyPropertyGroup();
 
    virtual void __fastcall Assign(TPersistent *Source);
 
__published:
    __property TPicture* ActiveImage = {read=FActiveImage, write=SetActiveImage};
    __property TPicture* InactiveImage = {read=FInactiveImage, write=SetInactiveImage};
 
    __property TNotifyEvent OnActiveImageChange = {read=FOnActiveImageChange, 
write=FOnActiveImageChange};
    __property TNotifyEvent OnInactiveImageChange = {read=FOnInactiveImageChange, 
write=FOnInactiveImageChange};
};
 
class PACKAGE TmyPanel : public TCustomPanel
{
private:
    TmyPropertyGroup *FmyProperties;
    TImage *FIndicatorImage;
    bool FImageState;
 
    void __fastcall ActiveImageChanged(TObject *Sender);
    void __fastcall InactiveImageChanged(TObject *Sender);
    bool __fastcall IsLoading();
    void __fastcall SetMyProperties(TmyPropertyGroup *Value);
    void __fastcall SetImageState(bool Value);
    void __fastcall UpdateIndicator();
 
protected:
    virtual void __fastcall Loaded();
 
public:
    __fastcall TmyPanel(TComponent *Owner);
    __fastcall ~TmyPanel();
 
__published:
    __property TmyPropertyGroup *Properties = {read=FmyProperties, write=SetMyProperties};
    __property bool ImageState = {read=FImageState, write=SetImageState};
};
 
...
 
__fastcall TmyPropertyGroup::TmyPropertyGroup(TmyPanel *Owner)
    : TPersistent(), FOwner(Owner)
{
    FActiveImage = new TPicture;
    FActiveImage->OnChange = &ActiveImageChanged;
 
    FInactiveImage = new TPicture;
    FInactiveImage->OnChange = &InactiveImageChanged;
}
 
__fastcall TmyPropertyGroup::~TmyPropertyGroup()
{
    delete FActiveImage;
    delete FInactiveImage;
}
 
void __fastcall TmyPropertyGroup::Assign(TPersistent *Source)
{
    TmyPropertyGroup *group = dynamic_cast<TmyPropertyGroup*>(Source);
    if (group)
    {
        FActiveImage->Assign(group->ActiveImage);
        FInactiveImage->Assign(group->InactiveImage);
    }
    else
        TPersistent::Assign(Source);
}
 
void __fastcall TmyPropertyGroup::ActiveImageChanged(TObject *Sender)
{
    if (FOnActiveImageChange)
        FOnActiveImageChange(this);
}
 
void __fastcall TmyPropertyGroup::InactiveImageChanged(TObject *Sender)
{
    if (FOnInactiveImageChange)
        FOnInactiveImageChange(this);
}
 
void __fastcall TmyPropertyGroup::SetActiveImage(TPicture *Value)
{
    FActiveImage->Assign(Value);
}
 
void __fastcall TmyPropertyGroup::SetInactiveImage(TPicture *Value)
{
    FInactiveImage->Assign(Value);
}
 
...
 
__fastcall TmyPanel::TmyPanel(TComponent *Owner)
    : TCustomPanel(Owner)
{
    FmyProperties = new TmyPropertyGroup;
    FmyProperties->OnActiveImageChangee = &ActiveImageChanged;
    FmyProperties->OnInactiveImageChange = &InactiveImageChanged;
 
    FIndicatorImage = new TImage(this);
    // set FIndicatorImage properties as needed...
}
 
__fastcall TmyPanel::~TmyPanel()
{
    delete FmyProperties;
}
 
void __fastcall TmyPanel::ActiveImageChanged(TObject *Sender)
{
    if ((!IsLoading()) && (FImageState))
        UpdateIndicator();
}
 
void __fastcall TmyPanel::InactiveImageChanged(TObject *Sender)
{
    if ((!IsLoading()) && (!FImageState))
        UpdateIndicator();
}
 
bool __fastcall TmyPanel::IsLoading()
{
    TComponentState CompState = ComponentState * (TComponentState() << csLoading 
<< csReading);
    return !CompState.Empty();
}
 
void __fastcall TmyPanel::Loaded()
{
    TCustomPanel::Loaded();
    UpdateIndicator();
}
 
void __fastcall TmyPanel::SetMyProperties(TmyPropertyGroup *Value)
{
    FmyProperties->Assign(Value);
}
 
void __fastcall TmyPanel::SetImageState(bool Value)
{
    if (FImageState != Value)
    {
        FImageState = Value;
        if (!IsLoading())
            UpdateIndicator();
    }
}
 
void __fastcall TmyPanel::UpdateIndicator()
{
    TPicture *pic = FImageState ? FmyProperties->ActiveImage : FmyProperties->InactiveImage;
    FIndicatorImage->Picture->Assign(pic);
}


--
Remy Lebeau (TeamB)
James Williams

Posts: 63
Registered: 8/22/13
Re: Properties of TImage not available in the IDE when embedded [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 12, 2016 4:28 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
James wrote:

The problem is that the properties that are TImage do not expose
any of the underlying properties, events in the property inspect at
design time.

Are you calling SetSubComponent(True) on them when creating them?

I have no access to it at all. Is there another approach that I should
be using to group embedded components such that their properties are
accessible by the main component in the property inspect at design time?

Why are you using TImage at all, and not TPicture instead? TImage is a visual
component, it should not be used for backing properties. TPicture should
be used instead. At runtime, your panel component can Assign() the appropriate
TPicture data to its internal TImage object for display purposes.

What I am trying to do is use two images that are stored in the TmyPropertyGroup
which is used to set the "Picture" of the FImageState in the TmyPanel.

This is done by the use of another property called ImageState which is a
bool type. If ImageState is true, then the displayed image on the panel
receives the FmyProperties->ActiveImage->Picture, whereas if ImageState
is false, then FImageState->Picture = FmyProperties->InactiveImage->Picture.

See, you are already using TPicture anyway, so you don't actually need TImage
at all, and should remove it, just use TPicture by itself.

Try something more like this:

class PACKAGE TmyPropertyGroup : public TPersistent
{
private:
    TPicture *FActiveImage;
    TPicture *FInactiveImage;
    TNotifyEvent FOnActiveImageChange;
    TNotifyEvent FOnInactiveImageChange;
 
    void __fastcall ActiveImageChanged(TObject *Sender);
    void __fastcall InactiveImageChanged(TObject *Sender);
    void __fastcall SetActiveImage(TPicture *Value);
    void __fastcall SetInactiveImage(TPicture *Value);
 
public:
    __fastcall TmyPropertyGroup();
    __fastcall ~TmyPropertyGroup();
 
    virtual void __fastcall Assign(TPersistent *Source);
 
__published:
    __property TPicture* ActiveImage = {read=FActiveImage, write=SetActiveImage};
    __property TPicture* InactiveImage = {read=FInactiveImage, write=SetInactiveImage};
 
    __property TNotifyEvent OnActiveImageChange = {read=FOnActiveImageChange, 
write=FOnActiveImageChange};
    __property TNotifyEvent OnInactiveImageChange = {read=FOnInactiveImageChange, 
write=FOnInactiveImageChange};
};
 
class PACKAGE TmyPanel : public TCustomPanel
{
private:
    TmyPropertyGroup *FmyProperties;
    TImage *FIndicatorImage;
    bool FImageState;
 
    void __fastcall ActiveImageChanged(TObject *Sender);
    void __fastcall InactiveImageChanged(TObject *Sender);
    bool __fastcall IsLoading();
    void __fastcall SetMyProperties(TmyPropertyGroup *Value);
    void __fastcall SetImageState(bool Value);
    void __fastcall UpdateIndicator();
 
protected:
    virtual void __fastcall Loaded();
 
public:
    __fastcall TmyPanel(TComponent *Owner);
    __fastcall ~TmyPanel();
 
__published:
    __property TmyPropertyGroup *Properties = {read=FmyProperties, write=SetMyProperties};
    __property bool ImageState = {read=FImageState, write=SetImageState};
};
 
...
 
__fastcall TmyPropertyGroup::TmyPropertyGroup(TmyPanel *Owner)
    : TPersistent(), FOwner(Owner)
{
    FActiveImage = new TPicture;
    FActiveImage->OnChange = &ActiveImageChanged;
 
    FInactiveImage = new TPicture;
    FInactiveImage->OnChange = &InactiveImageChanged;
}
 
__fastcall TmyPropertyGroup::~TmyPropertyGroup()
{
    delete FActiveImage;
    delete FInactiveImage;
}
 
void __fastcall TmyPropertyGroup::Assign(TPersistent *Source)
{
    TmyPropertyGroup *group = dynamic_cast<TmyPropertyGroup*>(Source);
    if (group)
    {
        FActiveImage->Assign(group->ActiveImage);
        FInactiveImage->Assign(group->InactiveImage);
    }
    else
        TPersistent::Assign(Source);
}
 
void __fastcall TmyPropertyGroup::ActiveImageChanged(TObject *Sender)
{
    if (FOnActiveImageChange)
        FOnActiveImageChange(this);
}
 
void __fastcall TmyPropertyGroup::InactiveImageChanged(TObject *Sender)
{
    if (FOnInactiveImageChange)
        FOnInactiveImageChange(this);
}
 
void __fastcall TmyPropertyGroup::SetActiveImage(TPicture *Value)
{
    FActiveImage->Assign(Value);
}
 
void __fastcall TmyPropertyGroup::SetInactiveImage(TPicture *Value)
{
    FInactiveImage->Assign(Value);
}
 
...
 
__fastcall TmyPanel::TmyPanel(TComponent *Owner)
    : TCustomPanel(Owner)
{
    FmyProperties = new TmyPropertyGroup;
    FmyProperties->OnActiveImageChangee = &ActiveImageChanged;
    FmyProperties->OnInactiveImageChange = &InactiveImageChanged;
 
    FIndicatorImage = new TImage(this);
    // set FIndicatorImage properties as needed...
}
 
__fastcall TmyPanel::~TmyPanel()
{
    delete FmyProperties;
}
 
void __fastcall TmyPanel::ActiveImageChanged(TObject *Sender)
{
    if ((!IsLoading()) && (FImageState))
        UpdateIndicator();
}
 
void __fastcall TmyPanel::InactiveImageChanged(TObject *Sender)
{
    if ((!IsLoading()) && (!FImageState))
        UpdateIndicator();
}
 
bool __fastcall TmyPanel::IsLoading()
{
    TComponentState CompState = ComponentState * (TComponentState() << csLoading 
<< csReading);
    return !CompState.Empty();
}
 
void __fastcall TmyPanel::Loaded()
{
    TCustomPanel::Loaded();
    UpdateIndicator();
}
 
void __fastcall TmyPanel::SetMyProperties(TmyPropertyGroup *Value)
{
    FmyProperties->Assign(Value);
}
 
void __fastcall TmyPanel::SetImageState(bool Value)
{
    if (FImageState != Value)
    {
        FImageState = Value;
        if (!IsLoading())
            UpdateIndicator();
    }
}
 
void __fastcall TmyPanel::UpdateIndicator()
{
    TPicture *pic = FImageState ? FmyProperties->ActiveImage : FmyProperties->InactiveImage;
    FIndicatorImage->Picture->Assign(pic);
}


--
Remy Lebeau (TeamB)

Thanks Remy, I will see if this resolves my issue. Yah, I did not think to use TPicture for the non-visual storage, which makes sense since I don't need the other visual properties and such that are part of TImage.

Regards,

James
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02