Runtime controls can provide a lot of flexibility and sometimes this is required. I spent a lot of time to understand the details of how this works. Below are the basics
- Runtime controls should be created
In the below code snipped, a group control is being used to add all the controls to. As the same group is being used multiple times the code clears off all the controls at the start and then adds new controls.
str controlName;
FormStringControl formBuildLookupControl, formBuildStringControl;
FormIntControl formBuildIntControl;
FormDateControl formBuildDateControl;
FormRealControl formBuildRealControl;
FormGroupControl FormBuildGroupControl;
//unload all the existing controls within the given group
while ( GroupVariables.controlCount() )
{
element.design().removeControl( GroupVariables.controlNum(1).id() );
}
_controlsMap = QtnPackageLineControls::loadControls( _pkgCode, _NewItem.data() );
_controlsEnumerator = _controlsMap.getEnumerator();
//add all the controls to the group
while ( _controlsEnumerator.moveNext() )
{
QtnPackageLineParams _controlParams = _controlsEnumerator.currentValue();
controlName = _controlsEnumerator.currentKey();
FormBuildGroupControl = GroupVariables.addControl( FormControlType::Group, strFmt("%1Group", controlName));
FormBuildGroupControl.caption( _controlParams.parmControlLabel() );
FormBuildGroupControl.visible(true);
switch (_controlParams.parmControlType() )
{
case QtnPackageConfigTypesEnum::Date:
FormBuildDateControl = FormBuildGroupControl.addControl( FormControlType::Date, controlName);
FormBuildDateControl.registerOverrideMethod( methodStr( FormDateControl, modified ), methodStr(QtnPackageConfigLookupValue, "DynamicsDateControl_modified"), runTimeMethods);
FormBuildDateControl.visible(true);
break;
case QtnPackageConfigTypesEnum::Integer:
formBuildIntControl = FormBuildGroupControl.addControl( FormControlType::Integer, controlName);
formBuildIntControl.registerOverrideMethod( methodStr( FormDateControl, modified ), methodStr(QtnPackageConfigLookupValue,"DynamicsIntControl_modified"), runTimeMethods);
formBuildIntControl.visible(true);
break;
case QtnPackageConfigTypesEnum::Lookup:
FormBuildStringControl = FormBuildGroupControl.addControl( FormControlType::String, controlName);
FormBuildStringControl.registerOverrideMethod(methodStr( FormStringControl, modified ), methodStr(QtnPackageConfigLookupValue,"DynamicsStringControl_modified"), runTimeMethods);
FormBuildStringControl.registerOverrideMethod(methodStr( FormStringControl, lookup ), methodStr(QtnPackageConfigLookupValue,"DynamicsStringControl_lookup"), runTimeMethods);
FormBuildStringControl.lookupOnly(true);
FormBuildStringControl.visible(true);
break;
case QtnPackageConfigTypesEnum::Real:
FormBuildRealControl = FormBuildGroupControl.addControl( FormControlType::Real, controlName);
FormBuildRealControl.registerOverrideMethod( methodStr( FormDateControl, modified ),methodStr(QtnPackageConfigLookupValue,"DynamicsRealControl_modified"), runTimeMethods);
FormBuildRealControl.visible(true);
break;
case QtnPackageConfigTypesEnum::String:
FormBuildStringControl = FormBuildGroupControl.addControl( FormControlType::String, controlName);
FormBuildStringControl.registerOverrideMethod(methodStr( FormStringControl, modified ), methodStr(QtnPackageConfigLookupValue,"DynamicsStringControl_modified"), runTimeMethods);
FormBuildStringControl.visible(true);
break;
}
}
- The registerOverrideMethod should be used to provide a callback method
When the controls are created the override method is also provided. There are multiple parts to the override methods as shown below:
formButtonControl.registerOverrideMethod(
methodStr(FormButtonControl,clicked), //method to override
methodStr(testClass,testMethod), //method to invoke
new testClass()); //object of class containing method
The registerOverideMethod is called using an instance of a control, so it already knows which source object is being overloaded. The rest of the parameters are used as follows:
- The first parameter identifies the method of this object to overload. The name of the method can be identified using the methodStr function; make sure to use the right control type class.
- The second parameter the target method to be called instead
- The third parameters identified the runtime object to find the target methods in
- The next step is to create the callback method that would be called at runtime on the control being created and loaded
public boolean DynamicsIntControl_modified(FormControl _control)
{
boolean ret = true;
info("control is modified");
return ret;
}
Below are some of the points to note about the runtime callback function:
- This method should always have a parameter of type FormControl type.
- The name of the method can be anything. The signature of the method can be determined by checking an actual method of a similar contol on the form.
Like in the above example we can create a modified method on a Integer type of control. Because the modified method of an integer control has a return value of boolean; we use the same return types in the callback method.