• Skip to main content
  • Skip to header right navigation
  • Skip to site footer
CDP Studio logo

CDP Studio

Software development tool for distributed control systems

  • Why CDP
    • Software developers
    • Automation engineers
    • Managers
  • Product
    • Design UI
    • Develop
    • Analyze and test
    • Deploy
    • Framework and toolbox
    • Compatibility
  • Services
  • Use cases
  • Pricing
  • Try CDP

CDP Studio Documentation

  • Examples and Tutorials
  • User Defined Structure Example B

User Defined Structure Example A User Defined Structure Example C

User Defined Structure Example B

Example B

Select UserComponentB under UserDefinedStructureLib

In Resource tree, CDPModel should have appeared. Right-click AggregateModel and select Add option in the context menu

Scroll down to Element-section and find the Element just added (AggregatedModel)

Change the Element name from AggregatedModel to UserNodesB

Once more in Resource tree, under CDPModel right-click AggregateModel and select Add option in the context menu

Scroll down to Element-section and find the Element just added (AggregatedModel)

In the AcceptsModel column, enter the model-name which shall be accepted ('UserDefinedStructureLib.UserNodeB')

Change the Element name from AggregatedModel to UserNodesB/UserNodeB

Note: It is important that changing the name is done last, because editing after entering a name containing '/' is not supported.

Note: Now you should build your library: Right-click UserDefinedStructureLib and select Build.

Select App under UserDefinedStructureSystem

In Resource tree, right-click UserComponentB under UserDefinedStructureLib and select Add

Select UserComponentB under App in UserDefinedStructureSystem

In top of the configuration area for UserComponentB, you can see an empty UserNodesB section.

In Resource tree, right-click UserNodeB under UserDefinedStructureLib and select Add

Add 2 more nodes of type UserNodeB, and give the names UserNodeB1, UserNodeB2 and UserNodeB3 to the newly added nodes.

If you now try to run the application without any modifications in the C++-code, no UserNodeB will show up:

Right click on UserDefinedStructureSystem and select Run & Connect

Select UserComponentB under App in UserDefinedStructureSystem

Changes to UserComponentB

The UserComponentB behavior is described by two C++ files UserComponentB.h under Headers, UserComponentB.cpp under Sources in the Code mode Project tree.

The UserComponentB configuration options for CDP Studio are described by the model file UserDefinedStructureLib.UserComponentB.xml under Other files Templates/Models.

The UserComponentB is referred to in the library meta file UserDefinedStructureLib.xml under Other files exposing the file as a user resource that can be added during configuration and in UserDefinedStructureLibBuilder.cpp builder class that is used to create instances during runtime startup.

UserComponentB in the Model File

The syntax of model files is detailed in help page: CDP Model syntax. The configuration done in start of Example B (adding 'AggregateModel' and configuring AcceptsModel), enables UserNodeB to be dragged into UserComponentB under section UserNodesB, during configuration:

<Element Name="UserNodesB" Property="0"></Element>
<Element Name="UserNodesB/UserNodeB" Property="0" AcceptsModel="UserDefinedStructureLib.UserNodeB"></Element>

The "Name" attribute in the Element defines the name used/generated in the configuration files - It can be named anything, except names already used in this model or its base model(s).

The Property="0" attribute makes the element a section definition and not a property element definition.

The AcceptsModel attribute lists one or more ; separated models that are aggregated by the user model. The model syntax provides also an alternative attribute called AcceptsBase that makes the section accept all models that inherit a given base model.

Note: The set of models the section accepts can't intersect with other sections in given model or its base models. This means that the same model can't be used in two different sections in the same view-level.

UserComponentB in C++ Files

To enable UserComponentB to show the nodes of type UserNodeB during Online view (when connected to the running application), we need to add some code. It is has three main items: the container used to keep track of the UserNodeB instances, custom XML configuration handling and exposing the container to serialization in StudioAPI (so they will show up with values in Studio).

Firstly, UserComponentB.h needs a container to hold the pointer to created instances of UserNodeB, but the UserNodeB class should be forward declared before the class definition starts.

Before class declaration:

class UserNodeB;

In class declaration:

protected:
    std::vector<UserNodeB*> m_userNodesB;

Secondly, UserComponentB.h/.cpp needs to override HandleXMLElement() to handle defined UserNodeB tags defined in the XML. The section in component xml-file for UserComponentB which we need to parse, looks like this:

UserComponentB.xml:

<UserNodesB>
  <UserNodeB Description="Simple node example." Model="UserDefinedStructureLib.UserNodeB" Name="UserNodeB1" UserAttribute="StringB1"></UserNodeB>
  <UserNodeB Description="Simple node example." Model="UserDefinedStructureLib.UserNodeB" Name="UserNodeB2" UserAttribute="StringB2"></UserNodeB>
  <UserNodeB Description="Simple node example." Model="UserDefinedStructureLib.UserNodeB" Name="UserNodeB3" UserAttribute="StringB3"></UserNodeB>
</UserNodesB>

UserComponentB.h:

    bool HandleXMLElement(XMLElementEx *pEx) override;

UserComponentB.cpp:

bool UserComponentB::HandleXMLElement(XMLElementEx *pEx)
{
    const XMLString& currentElement = pEx->GetName();

    if (currentElement == "UserNodesB") // this is just wrapper element for UserNode elements
        return false; //not done with handling, handleElement for childern also

    if (currentElement == "UserNodeB")
    {
        m_userNodesB.push_back(new UserNodeB(pEx, this));
        return true; // done with handling the structure
    }

    return CDPComponent::HandleXMLElement(pEx);
}

Thirdly, UserComponentB.h/.cpp needs to override FillNodeChildren() to expose UserNodeB instances as its children in StudioAPI during runtime.

UserComponentB.h:

    void FillNodeChildren(CDP::StudioAPI::NodeStream &serializer) const override;

UserComponentB.cpp:

void UserComponentB::FillNodeChildren(CDP::StudioAPI::NodeStream &serializer) const
{
    serializer.StdContainerStreamer(m_userNodesB);
    CDPComponent::FillNodeChildren(serializer);
}

To finish up, the class destructor should delete the nodes instantiated, and the UserNodeB header must be included in the UserComponentB.cpp file.

Changes to UserNodeB

The UserNodeB has similar definition files as UserComponentB: header, source and model. The only difference is that UserNodeB is not added to the Builder class. For the default UserNodeB in UserComponentB to work, the generated UserNodeB definition need no further changes.

Note: After the changes done in the C++ files (UserComponentB.h/.cpp), remember to build the library.

Configuring UserNodeB's Property Values and Show Values in Runtime

By default, a CDPNode created by the wizard has one property to contain a user-value (in addition to the standard attributes/properties called "Model" and "Description"). In the model-file, this property is called "UserAttribute" of type "string" with value "Simple attribute". To modify the value for the 3 UserNodeB in UserComponentB:

Select UserComponentB under App in UserDefinedStructureSystem

Find the "UserAttribute" column in "UserNodesB" section and change the value to "StringB1" for UserNodeB1.

Modify the UserAttribute value to "StringB2" and "StringB3" for the other nodes as well.

If you now try to run the application, nodes of type UserNodeB will show up in the configured section UserNodesB:

Right click on UserDefinedStructureSystem and select Run & Connect

Select UserComponentB under App in UserDefinedStructureSystem

The section UserNodesB shows the 3 nodes with correct values.

Example B-2

As mentioned earlier, a standard CDPNode created by the wizard has only one property to contain a user-value. This property is called "UserAttribute", and is of type string. Here is a short description of what to do, to add 2 new properties (one of type double and one of type int:

  • Select UserNodeB under UserDefinedStructureLib
  • In Resource tree, right-click PropertyAsAttribute under CDPModel and select Add option in the context menu
  • Add another PropertyAsAttribute
  • In the "Attributes" section, change the names of the newly added properties to MyDouble and MyInt. Change the Types to double and int, and set the Values to e.g. 3.14 and 7
  • Build your library (Right-click UserDefinedStructureLib and select Build)
  • Select UserComponentB under App in UserDefinedStructureSystem

Troubleshooting:

  • If the 2 new properties don't show up, righ-click the header containing all the other properties (like UserAttribute) and tick the 2 new properties. Then the 2 new properties will appear.
  • If the 2 new properties still don't show up, close the system (UserDefinedStructureSystem) and open the system again.
  • If these 2 properties had been added to a model used as a base-model, and you want these properties to show up in the models inheriting the base model, you have to change the DisplayHint in the "Attributes" section from Default to Important for the properties.

To make the 2 new properties appear also in Online view, you need to add some code in the C++-files: In UserNodeB.h, declare the 2 new property-members in the private section:

CDPProperty<double> myDouble;
CDPProperty<int> myInt;

In UserNodeB.cpp, the 2 new properties must be created. Update the end of UserNodeB constructor, so your constructor looks like this:

UserNodeB::UserNodeB(XMLElementEx* element, CDPBaseObject* owner)
{
    SetNodeOwner(owner);

    PropertyCreate(nodeName, this, "Name", e_PropertySaveOnChange, element);
    PropertyCreate(userAttribute, this, "UserAttribute", e_PropertySaveOnChange, element);
    auto flags = PropertyCreateFlags()|e_PropertyReadOnly;
    PropertyCreate(myDouble, this, "MyDouble", flags, element);
    PropertyCreate(myInt, this, "MyInt", flags, element);
}

The e_PropertyReadOnly will make the properties read-only in Online view

In UserNodeB.cpp, the 2 new properties must be serialized in FillNodeChildren(). Add the serialization of 'myDouble' and 'myInt' so FillNodeChildren() looks like this:

void UserNodeB::FillNodeChildren(CDP::StudioAPI::NodeStream &serializer) const
{
    serializer << AdoptedChild(nodeName) << AdoptedChild(userAttribute) << AdoptedChild(myDouble) << AdoptedChild(myInt);
}
  • Build your library (Right-click UserDefinedStructureLib and select Build)
  • Right click on UserDefinedStructureSystem and select Run & Connect
  • Select UserComponentB under App in UserDefinedStructureSystem

Troubleshooting:

  • If the 2 new properties don't show up, Stop the system (UserDefinedStructureSystem), close the system and open the system again. If you now select Run & Connect and then select UserComponentB under App in UserDefinedStructureSystem, the 2 new properties should appear.
  • If reopening the system did not help, try to restart CDP Studio

Files

  • UserComponentB.cpp
  • UserComponentB.h
  • UserNodeB.cpp
  • UserNodeB.h

User Defined Structure Example A User Defined Structure Example C

The content of this document is confidential information not to be published without the consent of CDP Technologies AS.

CDP Technologies AS, www.cdpstudio.com

Get started with CDP Studio today

Let us help you take your great ideas and turn them into the products your customer will love.

Try CDP Studio for free
Why CDP Studio?

CDP Technologies AS
Hundsværgata 8,
P.O. Box 144
6001 Ålesund, Norway

Tel: +47 990 80 900
E-mail: info@cdptech.com

Company

About CDP

Contact us

Services

Partners

Blog

Developers

Get started

User manuals

Support

Document download

Release notes

Follow CDP

    © Copyright 2021 CDP Technologies. Privacy and cookie policy.

    Return to top