Conclusion
At this point, we’re finished with the tutorial. I hope that this information was helpful. I’m certain that there are other ways of accomplishing the goal we’ve achieved here; if you want to improve the code or expand it, feel free. One thing that I haven’t yet incorporated is a method to handle row spans. Perhaps that will be the next step. Good luck!
Meanwhile, Listing 7 shows the entire TableViewer.as class. The source.zip file contains all of the source code for downloading.
Listing 7 The TableViewer.as class.
import com.xfactorstudio.xml.xpath.XPath;
class com.extension.TableViewer {
// define global variables
private var TableFile:XML;
private var TimeLine:MovieClip;
private var Base_mc:MovieClip;
private var Border_mc:MovieClip;
private var Boxes_mc:MovieClip;
private var AllBoxes:Array;
private var AllTexts:Array;
private var Rows:Array;
private var Cells:Array;
private var CellsMax:Array;
private var CellNumbers:Array;
private var AllTextBoxes:Array;
private var BackgroundColor:Number;
private var CellWidth:Number;
private var TableWidth:Number;
private var TableHeight:Number;
private var TablePadding:Number;
//**********************************
// pass in a movie clip, the xml, and the desired width of the table
//**********************************
public function TableViewer(mc:MovieClip, xml:XML, tableWidth:Number, maxTableHeight:Number) {
TimeLine = mc;
TableFile = new XML(xml.toString());
AllBoxes = new Array();
AllTexts = new Array();
Cells = new Array();
CellsMax = new Array();
CellNumbers = new Array();
AllTextBoxes = new Array();
BackgroundColor;
TableWidth = tableWidth;
TablePadding;
// create necessary clips
Base_mc = TimeLine.createEmptyMovieClip("base_clip", TimeLine.getNextHighestDepth() );
Border_mc = Base_mc.createEmptyMovieClip("borders_clip", Base_mc.getNextHighestDepth() );
Boxes_mc = Base_mc.createEmptyMovieClip("boxes_clip", Base_mc.getNextHighestDepth() );
TableController();
}
private function ExtractColor(color:Array):Number {
// removes the # sign and returns hex value as a Number type
if(color) {
var colorStr:String = color[0].toString();
var stringTest:Number = colorStr.indexOf("#");
if (stringTest != -1) {
var colorValue:String = "0x"+colorStr.substring(stringTest+1, colorStr.length);
}
}
var returnColor:Number = parseInt(colorValue);
return returnColor;
}
//**********
// TableController method ensures that methods are called in the proper order
//**********
private function TableController() {
var tableBuilt:Boolean = TableBuilder();
if (tableBuilt == true) {
CreateTextBoxes();
CreateAndPositionGrid();
}
}
//**********
// gather all of the table data from the table source file and write that data into arrays
//**********
private function TableBuilder():Boolean {
// if TableWidth has not been set, look for a width attribute, capture it, else set the table to 20 less than the Stage.width
if (!TableWidth) {
var tempWidth:Array = XPath.selectNodes(TableFile.firstChild, "/table/@width");
if (tempWidth[0] != undefined) {
TableWidth = parseInt(tempWidth[0]);
} else {
TableWidth = Stage.width - 20;
}
}
// if the table has a padding attribute set, capture it, else set the padding to 0
var tempPadding:Array = XPath.selectNodes(TableFile.firstChild, "/table/@padding");
if (tempPadding[0] != undefined) {
TablePadding = parseInt(tempPadding[0]);
} else {
TablePadding = 0;
}
// get the background color for entire table, else set it to white
var bg = XPath.selectNodes(TableFile.firstChild, "/table/@bgcolor");
if (bg.length > 0 ) {
BackgroundColor = ExtractColor(bg);
} else {
BackgroundColor = 0xffffff;
}
// grab all the rows into an array, then use rows to grab all the cells into an array
Rows = XPath.selectNodes(TableFile.firstChild, "/table/tr");
// foreach row, get all the values for all the cells
for (var x:Number = 0; x< Rows.length; x++) {
var currentRow:Number = x+1;
// get cells from td and th tags
Cells.push(XPath.selectNodes(TableFile.firstChild, "/table/tr[position() = "+ currentRow +"]/td | /table/tr[position() = "+ currentRow +"]/th"));
}
//***********************
// goal: determine which row has the most cells so we can calculate how wide to make individual cells
// how:
// push number of cells per row onto CellsTotal
// sort by number :NUMERIC
// reverse to put highest number first...
// use CellWidth to calculate max cell widths...
//***********************
for (var x:Number = 0; x<Cells.length; x++) {
CellsMax.push(Cells[x].length);
CellNumbers.push(Cells[x].length);
}
CellsMax.sort(Array.NUMERIC);
CellsMax.reverse();
CellWidth = Math.floor(TableWidth / CellsMax[0]);
return true;
}
//**********
// create the text boxes based on the Cells multidimensional array (tr1(td1,td2), tr2(td1,td2) ...
//**********
private function CreateTextBoxes() {
for (var x:Number = 0; x<Cells.length; x++) {
// used to create multi-dimensional array AllTextBoxes at the end of the for loop
var textBoxArray:Array = new Array();
var cellAlignment:String = "center";
var boxArray:Array = new Array();
var textBoxArray:Array = new Array();
// create textboxes and insert values
for (var i:Number = 0; i<Cells[x].length; i++) {
var currentCell:Number = i + 1;
// create text clips and populate
var currentBox:MovieClip = Boxes_mc.createEmptyMovieClip("box"+x+"_"+i, Boxes_mc.getNextHighestDepth());
var currentText:Object = currentBox.createTextField("cell_txt", currentBox.getNextHighestDepth(), 0, 0, CellWidth, 125);
boxArray.push(currentBox);
textBoxArray.push(currentText);
currentText.multiline = true;
currentText.wordWrap = true;
currentText.autoSize = "center";
currentText.border = false;
currentText.html = true;
var formatting = new TextFormat();
formatting.color = 0x333333;
formatting.font = "verdana";
formatting.size = 10;
formatting.align = cellAlignment;
currentText.htmlText = Cells[x][i];
currentText.setTextFormat(formatting);
}
// textBoxArray contains all movieClip path for the textFields in a particular row
// push these onto AllTextBoxes to have them all in one place
// for use in CreateAndPositionGrid
AllBoxes.push(boxArray);
AllTexts.push(textBoxArray);
}
}
private function CreateAndPositionGrid() {
var rHeight:Number = 0;
var finalRowHeights:Array = new Array();
finalRowHeights.push(0);
var finalCellWidths:Array = new Array();
for (var x:Number = 0; x < Cells.length; x++) {
var colCounter:Number = 0;
var cellHeights:Array = new Array();
var cellWidths:Array = new Array();
for (var i:Number = 0; i < Cells[x].length; i++) {
var curRow:Number = x+1;
var curCell:Number = i+1;
var colspanValue:Array = XPath.selectNodes(TableFile.firstChild, "/table/tr[position() = "+ curRow +"]/td[position() = "+ curCell +"]/@colspan");
var colSpan:Number = 1;
// if colspan exists
if (colspanValue.length != 0) {
colSpan = parseInt(colspanValue[0]);
}
AllBoxes[x][i]._x = (colCounter*CellWidth)*colSpan;
AllBoxes[x][i]._y = rHeight;
var calTextWidth:Number;
if (colspanValue.length != 0) {
colCounter = colSpan;
calTextWidth = colCounter*CellWidth;
AllTexts[x][i]._width = calTextWidth;
} else {
colCounter++;
}
cellHeights.push(AllTexts[x][i]._height);
cellWidths.push(AllTexts[x][i]._width);
}
// sort rowHeights to find the highest cell height
cellHeights.sort(Array.NUMERIC);
cellHeights.reverse();
var curRowMaxHeight:Number = Math.floor(cellHeights[0]);
// increment rHeight with current row’s maximum height
rHeight = rHeight + curRowMaxHeight;
finalRowHeights.push(rHeight);
finalCellWidths.push(cellWidths);
// draw the outer and row borders
Border_mc.lineStyle(1, 0x999999, 100);
Border_mc.moveTo(0, 0);
Border_mc.lineTo(TableWidth, 0);
Border_mc.lineTo(TableWidth, rHeight);
Border_mc.lineTo(0, rHeight);
Border_mc.lineTo(0, 0);
}
// draw inner vertical lines
for (var n:Number = 0; n<finalRowHeights.length; n++) {
Border_mc.lineStyle(1, 0x999999, 100);
var cellCalc:Number = 0;
for (var z:Number = 0; z<finalCellWidths[n].length-1; z++) {
cellCalc = cellCalc + parseInt(finalCellWidths[n][z]);
Border_mc.moveTo(cellCalc, finalRowHeights[n]);
Border_mc.lineTo(cellCalc, finalRowHeights[n+1]);
}
}
}
}
