Updating AMX TableLayouts dynamically with Kadene's 2D Algorithm sample
Now we will learn how to change dynamically some MAF AMX components. There we go:
Create classes
To start with the table structure we are going to create one class for the entire table called TableSum and other for the cells called CellNumber.
public class TableSum {
CellNumber[] TableRow1 = new CellNumber[5];
CellNumber[] TableRow2 = new CellNumber[5];
CellNumber[] TableRow3 = new CellNumber[5];
CellNumber[] TableRow4 = new CellNumber[5];
CellNumber[] TableRow5 = new CellNumber[5];
CellNumber[] TableRow6 = new CellNumber[5];
CellNumber[] TableRow7 = new CellNumber[5];
CellNumber[] TableRow8 = new CellNumber[5];
CellNumber[] TableRow9 = new CellNumber[5];
CellNumber[] TableRow10 = new CellNumber[5];
String resultSum="";
public class CellNumber {
String number;
String color;
Basically the table contains 10 rows and 5 columns. Every cell contains 2 fields a number and a color.
Create Data Controls
To map the table class over the interface we will create one data control called TableSum.
Create TableLayout
Now, we create a TableLayout and we should map every TableRow of Data Controls to each rowLayout.
<amx:tableLayout id="tl1" borderWidth="1" width="100%">
<amx:rowLayout id="rl1">
<amx:iterator var="row" value="#{bindings.tableRow11.collectionModel}" id="i1">
<amx:cellFormat id="cf1" halign="center">
<amx:outputText value="#{row.number}" id="ot2" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
<amx:rowLayout id="rl2">
<amx:iterator var="row" value="#{bindings.tableRow21.collectionModel}" id="i2">
<amx:cellFormat id="cf2" halign="center">
<amx:outputText value="#{row.number}" id="ot3" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
<amx:rowLayout id="rl3">
<amx:iterator var="row" value="#{bindings.tableRow31.collectionModel}" id="i3">
<amx:cellFormat id="cf3" halign="center">
<amx:outputText value="#{row.number}" id="ot4" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
<amx:rowLayout id="rl4">
<amx:iterator var="row" value="#{bindings.tableRow41.collectionModel}" id="i4">
<amx:cellFormat id="cf4" halign="center">
<amx:outputText value="#{row.number}" id="ot5" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
<amx:rowLayout id="rl5">
<amx:iterator var="row" value="#{bindings.tableRow5.collectionModel}" id="i5">
<amx:cellFormat id="cf5" halign="center">
<amx:outputText value="#{row.number}" id="ot6" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
<amx:rowLayout id="rl6">
<amx:iterator var="row" value="#{bindings.tableRow6.collectionModel}" id="i6">
<amx:cellFormat id="cf6" halign="center">
<amx:outputText value="#{row.number}" id="ot7" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
<amx:rowLayout id="rl7">
<amx:iterator var="row" value="#{bindings.tableRow7.collectionModel}" id="i7">
<amx:cellFormat id="cf7" halign="center">
<amx:outputText value="#{row.number}" id="ot8" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
<amx:rowLayout id="rl8">
<amx:iterator var="row" value="#{bindings.tableRow8.collectionModel}" id="i8">
<amx:cellFormat id="cf8" halign="center">
<amx:outputText value="#{row.number}" id="ot9" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
<amx:rowLayout id="rl9">
<amx:iterator var="row" value="#{bindings.tableRow9.collectionModel}" id="i9">
<amx:cellFormat id="cf9" halign="center">
<amx:outputText value="#{row.number}" id="ot10" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
<amx:rowLayout id="rl10">
<amx:iterator var="row" value="#{bindings.tableRow10.collectionModel}" id="i10">
<amx:cellFormat id="cf10" halign="center">
<amx:outputText value="#{row.number}" id="ot11" inlineStyle="color:#{row.color};"/>
</amx:cellFormat>
</amx:iterator>
</amx:rowLayout>
</amx:tableLayout>
Add action button
To update programatically, we will add a button from a method that belongs to TableSum class called runAlgorithm.
public void runAlgorithm(){
// Modify the array's elements to now hold the sum
// of all the numbers that are above that element in its column
int N=10,M=5;
int max_ending_here, max_so_far, maximum = Integer.MIN_VALUE;
int xBottom=0,yBottom=0,xTop=0,yTop=0;
int xBottomAux=0,yBottomAux=0,xTopAux=0,yTopAux=0,yTopAuxOld=0,yTopAuxNew=0;
for (int startx = 0; startx < N; startx++) {
int [] sum= new int[N];
for (int x = startx; x < N; x++) {
max_ending_here = 0;
max_so_far = Integer.MIN_VALUE;
yTopAuxOld=0;yTopAuxNew=0;
for (int y = 0; y < M; y++) {
sum[y] += new Integer(FullTable[x][y].getNumber());
max_ending_here = Math.max(0, max_ending_here + sum[y]);
if (0==max_ending_here){
yTopAuxNew=y+1<M?y+1:yTopAuxOld;
}
if (max_so_far<max_ending_here){
xTopAux=startx;
xBottomAux=x;
yBottomAux=y;
yTopAux=yTopAuxOld;
yTopAuxOld=yTopAuxNew;
}
max_so_far = Math.max(max_so_far, max_ending_here);
}
if (max_so_far>maximum){
xTop=xTopAux;
xBottom=xBottomAux;
yTop=yTopAux;
yBottom=yBottomAux;
}
maximum = Math.max(maximum, max_so_far);
}
}
propertyChangeSupport.firePropertyChange("resultSum", "zz", maximum +" ("+xTop+","+yTop+") ("+xBottom+","+yBottom+")");
paintResult(xTop,yTop,xBottom,yBottom);
}
Also, we are adding the result in the resultSum variable.
<amx:tableLayout id="tl2" width="100%">
<amx:rowLayout id="rl11">
<amx:cellFormat id="cf11" halign="center">
<amx:commandButton actionListener="#{bindings.runAlgorithm.execute}" text="run Algorithm"
disabled="#{!bindings.runAlgorithm.enabled}" id="cb1"/>
</amx:cellFormat>
</amx:rowLayout>
</amx:tableLayout>
<amx:outputText value="#{bindings.resultSum.inputValue}" id="ot12"/>
Refresh components
To refresh amx components we can use ProviderChangeSupport and PropertyChangeSupport.
- PropertyChangeSupport for attributes like String, Boolean, Integer, etc.
- ProviderChangeSupport for collections like arrays, collections, etc.
First we should add the following lines to the TableSum Class:
protected transient ProviderChangeSupport providerChangeSupport = new ProviderChangeSupport(this);
private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
public void addProviderChangeListener(ProviderChangeListener l) {
providerChangeSupport.addProviderChangeListener(l);
}
public void removeProviderChangeListener(ProviderChangeListener l) {
providerChangeSupport.removeProviderChangeListener(l);
}
public void addPropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.removePropertyChangeListener(l);
}
Then for every refreshing we can use the following methods.
For every table rows:
providerChangeSupport.fireProviderRefresh("tableRow1");
For result message:
propertyChangeSupport.firePropertyChange("resultSum", "oldValue", maximum +" ("+xTop+","+yTop+") ("+xBottom+","+yBottom+")");
Testing
Finally, we test the sample application
Before run algorithm:
After run algorithm:
Basically, the algorithm let us to get the max sum of a 2D array in a complexity O(n^3).
This time the result was 108 and the rectangle goes from Top-Left (1,1) to Bottom-right (9,3) colored with blue.
You can download the project Here