|
|
Re: Adding dynamic UI elements in scout [message #1235820 is a reply to message #1234688] |
Sat, 25 January 2014 11:19 |
|
Hi guys
A form initializes its fields on creation time. During that time you can inject custom fields using injectFields as explained here here. Afterwards you cannot add or remove fields, you can set them to visible / invisible though.
Another approach would be to use an editable table (set getConfiguredEditable of the columns to true) or to use a wrapped form field as João suggests.
-
Claudio
|
|
|
Re: Adding dynamic UI elements in scout [message #1384258 is a reply to message #1235820] |
Wed, 28 May 2014 14:42 |
João Rebelo Messages: 28 Registered: December 2013 |
Junior Member |
|
|
Hi,
We would like to share a solution for this issue! Actually it's possible to extend Scout so that we can indeed have a dynamic Group Box!
Allow me to demonstrate:
/**
* Add new field to the group box
*
* @param theFormField the form field
*/
public void addField(IFormField theFormField) {
initNewField(theFormField);
rebuildFieldGrid();
setNewField(theFormField);
}
private void initNewField(IFormField theFormField) {
try {
theFormField.setParentFieldInternal(this);
myField.setFormInternal(this.getForm());
theFormField.initField();
AbstractCompositeField anAbstractCompositeField = this;
Field allFields = AbstractCompositeField.class.getDeclaredField("m_fields");
allFields.setAccessible(true);
IFormField[] m_fields = Arrays.copyOf(getFields(), getFields().length + 1);
m_fields[getFields().length] = theFormField;
allFields.set(anAbstractCompositeField, m_fields);
}
catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException theException) {
LOG.error("Not Possible to Access SuperClass AbstractCompositeField m_fields", theException);
throw new RuntimeException(theException);
}
catch (ProcessingException theException) {
LOG.error("Error processing abstractQueryFilterDesignerField ", theException);
throw new RuntimeException(theException);
}
}
/**
* This method sends the new Form Field to be created in the UI layer
*
* @param theNewFormField the new Form Field
*/
protected void setNewField(IFormField theNewFormField) {
propertySupport.setProperty(PROP_NEW_FIELD, theNewFormField);
}
So this is our extension to the GroupBox. The trick here is that we have to access the private m_fields variable to add our own field, and then call the rebuildFieldGrid method.
Speaking in UI terms, this would be more or less equivalent to calling a "layout(true, true)" after adding a field in a Composite
Also very important detail is that each Field must be setted with:
the correct parent field,
the correct form where he belongs,
and finally be initialized (initField method).
With this in place, to add a new Field would be as easy as:
MyField myField = new MyField();
myDynamicGroupBox.addField(myField);
Same kind of solution can be used to remove elements, add multiple elements, re-sort the current elements (moving them in m_fields list), and so on.
Done with the modelling part we now need to review the rendering side of it. We've actually implemented renderings for SWT and RAP.
Follows the SWT implementation:
/**
* The Group Box Composite where fields are added.
*/
protected Composite m_swtBodyPart;
private ScrolledFormEx m_scrolledForm;
/**
* On initialization we'll need to get access to the composite where all fields are added in Scout.
* Then we need to process the fields that might already have been dynamically added before the UI rendering initialization
*/
@Override
protected void initializeSwt(Composite theParent) {
super.initializeSwt(theParent);
try {
Field aComposite = SwtScoutGroupBox.class.getDeclaredField("m_swtBodyPart");
aComposite.setAccessible(true);
Composite aCompositeToAdd = (Composite) aComposite.get(this);
setM_swtBodyPart(aCompositeToAdd);
//Assumes using scrolled forms
m_scrolledForm = (ScrolledFormEx) theParent.getParent().getParent();
// FIELDS:
List<IFormField> allFields = ((IFormField) getScoutObject()).getFields();
for (IFormField aField : allFields) {
addNewFieldForm(aField);
}
}
catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException theException) {
LOG.error("Not Possible to Access SuperClass SwtScoutGroupBox m_swtBodyPart", theException);
throw new RuntimeException(theException);
}
catch (ClassCastException theException) {
LOG.error("No scroll found in parent hierarchy ! ", theException);
throw new RuntimeException(theException);
}
}
@Override
protected void handleScoutPropertyChange(String theName, Object theValue) {
if (theName.equals(PROP_NEW_FIELD)) {
if (theValue != null && (theValue instanceof IFormField)) {
addNewFieldForm((IFormField) theValue);
refresh();
}
}
else {
super.handleScoutPropertyChange(theName, theValue);
}
}
/**
* Add new field form.
* Notice the Scout Field Grid Data that needs to be created so that all Scout layout properties are correctly used.
* @param theField the IFormField
*/
public void addNewFieldForm(IFormField theField) {
ISwtScoutFormField aSwtScoutComposite = getEnvironment().createFormField(m_swtBodyPart, theField);
SwtScoutFormFieldGridData aLayoutData = new SwtScoutFormFieldGridData(theField);
aSwtScoutComposite.getSwtContainer().setLayoutData(aLayoutData);
//map our dynamic fields into the its models - Useful for removal afterwards
fieldMap.put(theField, aSwtScoutComposite);
}
/**
* Refresh this box
* If not using a scrolled form then some kind of parent layout or refresh should be used
*/
protected void refresh() {
m_scrolledForm.reflow(true);
}
And the RAP implementation with some changes:
@Override
protected void initializeUi(Composite theParent) {
super.initializeUi(theParent);
try {
Field aComposite = RwtScoutGroupBox.class.getDeclaredField("m_bodyPart");
aComposite.setAccessible(true);
setM_bodyPart((Composite) aComposite.get(this));
//Assumes using scrolled forms
m_scrolledComposite = (ScrolledComposite) theParent.getParent();
// FIELDS:
List<IQueryFilterField> allFiltersFields = ((AbstractQueryFilterDesignerBox) getScoutObject()).getFilterFieldList();
for (IQueryFilterField aField : allFiltersFields) {
addNewFieldForm((IFormField) aField);
}
}
catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException theException) {
LOG.error("Not Possible to Access SuperClass SwtScoutGroupBox m_swtBodyPart", theException);
throw new RuntimeException(theException);
}
catch (ClassCastException theException) {
LOG.error("No scroll found in parent hierarchy ! ", theException);
throw new RuntimeException(theException);
}
}
/**
* Add new field form
*
* @param theField the IFormField
*/
public void addNewFieldForm(IFormField theField) {
IRwtScoutFormField aRwtScoutComposite = getUiEnvironment().createFormField(m_bodyPart, theField);
RwtScoutFormFieldGridData aLayoutData = new RwtScoutFormFieldGridData(theField);
aRwtScoutComposite.getUiContainer().setLayoutData(aLayoutData);
fieldMap.put(theField, aRwtScoutComposite);
}
private void refresh() {
if (m_scrolledComposite != null) {
int aReceiverBorderWidth;
try {
aReceiverBorderWidth = m_scrolledComposite.getBorderWidth();
}
catch (Exception theException) {
aReceiverBorderWidth = SWT.DEFAULT;
LOG.error("Not possible to calculate the receiver border width.", theException);
}
m_scrolledComposite.setMinSize(m_scrolledComposite.computeSize(aReceiverBorderWidth, SWT.DEFAULT));
m_scrolledComposite.layout(true, true);
}
getUiContainer().layout();
if (parentDynamicBox != null) {
parentDynamicBox.refresh();
}
}
@Override
protected void handleScoutPropertyChange(String theName, Object theValue) {
if (theName.equals(IQueryFilterDesignerBox.PROP_NEW_FIELD)) {
if (theValue != null && (theValue instanceof IFormField)) {
addNewFieldForm((IFormField) theValue);
refresh();
}
}
else {
super.handleScoutPropertyChange(theName, theValue);
}
}
Essentially the only rendering differences would be on the way the refresh is done, but very similar code in both solutions.
Just a warning/notice: Keep in mind that this solution makes use of Scout internals so it might break if some internal logic changes or variables are simply renamed.
Regards,
João Rebelo
|
|
|
Powered by
FUDForum. Page generated in 0.03386 seconds