This function is a bit long, so I'm going to break it up with explanations of individual pieces, rather than give you a long block of code and then a long block of explanatory text. Hopefully this won't be confusing and will be easier to follow without making you scroll up and down to match the text with the code.
private function buildResults():void{
  // If the boolean firstPage is true we start from scratch
  if(firstPage){
    // resultsTop will be a container to hold our next/prev widget and the column titles
    resultsTop = new Sprite();
    resultsTop.x = 0;
    resultsTop.y = 40;
    addChildAt(resultsTop, 0);
               
    xPos = 0;
    yPos = 0;


The first thing we do is check our firstPage variable. If it is true, meaning that there is nothing on screen yet, then we create our resultsTop Sprite. This will be the container that will hold all the stuff that makes up our results header. The reason we have two containers - resultsTop and resultsHolder - is because when we go to the second page of a results set we don't need to change the header information. Keeping the two
containers separate gives us this flexibility. We position our resultsTop at an x position of 0 and a y position of 40, and use the addChildAt function to place it on the bottom of the display stack, 0. In this demonstration it is not necessary to use the addChildAt, but, depending on what other things you may be adding later on, it can be handy to have these elements underneath everything else. In any case, it does no harm.

Now we set our variables xPos and yPos to 0. These co-ordinates are now relative to the resultsTop container, not the stage.
// If the boolean useNP is true, we need the Next/Prev widget, so build it now
    if(useNP){
      itemsToShow = maxNum;
      npT = new NextPrev(numSongs, maxNum, maxNum, 0x000000, 0x000000);
      npT.x = (stage.stageWidth - (npT.width - 40))/2;
      npT.y = yPos;
      // If you want to show the next/Prev widget on both the top and the bottom of your results give it a name
      npT.name = "NPT";
      npT.addEventListener(CustomEvent.CUSTOM, reBuild, false, 0, true);
      resultsTop.addChild(npT);
           
      yPos += 30;
    }


We check our variable useNP, and, if it is true, we set up the variables we need to interact with our NextPrev class. The variable itemsToShow refers to the maximum number of items to show at one time, and so is set to our maxNum variable.

Now we create our top instance of the NextPrev class, called npT, and pass these variables along to the NextPrev's constructor function:
numSongs - the total number of songs in this result set
maxNum - the maximum number of items to show at once
maxNum - represents the items showing, and is the same number at first as the previous variable
0x000000 - this is our text color
0x000000 - this is the text color for the button labels

Then we position our NextPrev instance. The npT's x property is set up to be centered on the page. We take the stage.stageWidth property and subtract the npT's width - 40 and then divide that result by 2. The reason for the -40 from the npT's width is because the last item to be set up in the NextPrev class is a button, and even though the width of that button is declared to be 60, Flash seems to stick with it's default button
width of 100. So, 100 - 60 = 40. Strange, but true. Our y position is just simply our yPos variable. Now, if you are going to be using both a top and a bottom instance of the NextPrev class you will want to give the instance a name. The name value is arbitrary, and I've called it NPT. This is just so we will know which instance - top or bottom - has been clicked. Then we add an event listener using our CustomEvent class, which we will go into in more detail at the end of this function. Finally, we add the npT instance to the resultsTop container, so that it is a child of the resultsTop Sprite, and then we add 30 to our yPos variable.
titleHead = new TextField();
    titleHead.x = xPos;
    titleHead.y = yPos;
    titleHead.width = 120;
    titleHead.height = 20;
    titleHead.border = true;
    titleHead.text = "Track Title";
    titleHead.setTextFormat(titleFormat);
    resultsTop.addChild(titleHead);
           
    xPos += 120;
               
    timeHead = new TextField();
    timeHead.x = xPos;
    timeHead.y = yPos;
    timeHead.width = 50;
    timeHead.height = 20;
    timeHead.border = true;
    timeHead.text = "Time";
    timeHead.setTextFormat(titleFormatC);
    resultsTop.addChild(timeHead);
           
    xPos += 50;

    composerHead = new TextField();
    composerHead.x = xPos;
    composerHead.y = yPos;
    composerHead.width = 130;
    composerHead.height = 20;
    composerHead.border = true;
    composerHead.text = "Composer";
    composerHead.setTextFormat(titleFormat);
    resultsTop.addChild(composerHead);
           
    xPos += 130;
           
    descHead = new TextField();
    descHead.x = xPos;
    descHead.y = yPos;
    descHead.width = 160;
    descHead.height = 20;
    descHead.border = true;
    descHead.text = "Description";
    descHead.setTextFormat(titleFormat);
    resultsTop.addChild(descHead);
           
    xPos += 160;
               
    buyHead = new TextField();
    buyHead.x = xPos;
    buyHead.y = yPos;
    buyHead.width = 40;
    buyHead.height = 20;
    buyHead.border = true;
    buyHead.text = "Buy";
    buyHead.setTextFormat(titleFormatC);
    resultsTop.addChild(buyHead);
           
    xPos = 0;
    yPos += 61;


Now we begin setting up our headings. First comes the titleHead TextField which holds the words "Track Title". This gets added as a child to our resultsTop container and uses the established xPos and yPos variables to position it. We continue on down the line adding the timeHead TextField next, then the composerHead, descHead,and buyHead Textfields.When we are done all that, we reset our xPos to 0 and add 61 to our yPos.
// If the boolean firstPage is not true, then we don't have to add all of the above
    }else if(!firstPage){
      //If the boolean useNP is true, set up our x and y positions to take the next/prev widget into account
      if(useNP){
        xPos = 0;
        yPos = 91;
       //If the boolean useNP is not true, our x and y positions only need to take the column headers into account
      }else{
        xPos = 0;
        yPos = 61;
      }
    }
    // Set up our bar colors and make the current color of our barColor variable equal to the first color
    var bar1Color:Number = 0xFFF7E6;
    var bar2Color:Number = 0xFEE4AB;
    var barColor:Number = bar1Color;
           
    // The resultsHolder will be the container to hold all of our results
    resultsHolder = new Sprite();
    resultsHolder.x = xPos;
    resultsHolder.y = yPos;
    addChildAt(resultsHolder, 0);
   
    yPos = 0;
    // Initialize our arrays for the bars and the column headers
    barArray = new Array();
    titleArray = new Array();
    composerArray = new Array();
    descArray = new Array();
    songLengthArray = new Array();
    buyArray = new Array();


If this is not the first page, then we don't need to add all the headings, but we need to know whether useNP is true so that we can take the space it uses into account. If useNP is true, then we reset our xPos to 0 and add 91 to our yPos, otherwise if useNP is false we reset our xPos to 0 and only add 61 to our yPos. In case you're wondering where the number 61 comes from, remember that we have our music buttons and our Item to Show occupying the first 40 pixels, then we have our headings which take up another 20 pixels, and then a 1 pixel space just because it looks better.

Next we give our bar1Color and bar2Color variables some color values. These bars will be Sprites that sit underneath each row and help to separate the results from one another with the use of alternating colors. Then we set our barColor variable to the value of bar1Color.

Now we get onto setting up our results list. We start by creating the resultsHolder Sprite to act as the container for the whole mess. We position it using our xPos and yPos variables, then add it the stage using addChildAt and giving it a spot in the display list of 0. If you remember, we set our resultsTop to this same position. With the resultsHolder now occupying 0, our resultsTop is automatically pushed into position 1.

Again, remember that the xPos and yPos positions will now be relative to our resultsHolder container, not the stage, so we reset our yPos to 0. Our xPos is already 0, so we are good to go there. Next we initialize the arrays we'll be using.
// Now we display the results
    for(var i:int = itemStart; i < itemsToShow; i++){
               
      // First we create the bar so that it will sit underneath the text
      barArray[i] = createSprite(barColor, 500, 24, xPos, yPos);
      resultsHolder.addChild(barArray[i]);
      // I want the text to center itself vertically inside the bar, so I add 2 pixels to the y position
      yPos += 2;
      // We make an array of text fields to hold our Song Title
      // Note that we use TextFieldAutoSize.LEFT for the autoSize property. With the multiline and wordWrap properties set to true
      // this will force the text field down to accommodate extra text
      titleArray[i] = new TextField();
      titleArray[i].x = xPos;
      titleArray[i].y = yPos;
      titleArray[i].width = 120;
      titleArray[i].height = 20;
      titleArray[i].multiline = true;
      titleArray[i].wordWrap = true;
      titleArray[i].autoSize = TextFieldAutoSize.LEFT;
      titleArray[i].text = musicInfoArray[i].Track;
      titleArray[i].setTextFormat(titleFormat);
      resultsHolder.addChild(titleArray[i]);
               
      xPos += 120;
      // Next we make an array of text fields to hold our Track Length
      songLengthArray[i] = new TextField();
      songLengthArray[i].x = xPos;
      songLengthArray[i].y = yPos;
      songLengthArray[i].width = 50;
      songLengthArray[i].height = 20;
      songLengthArray[i].text = musicInfoArray[i].TrackLength;
      songLengthArray[i].setTextFormat(titleFormatC);
      resultsHolder.addChild(songLengthArray[i]);
               
      xPos += 50;
      // Next we make an array of text fields to hold our Composer names
      // Note that once again we use TextFieldAutoSize.LEFT for the autoSize property
      composerArray[i] = new TextField();
      composerArray[i].x = xPos;
      composerArray[i].y = yPos;
      composerArray[i].width = 130;
      composerArray[i].height = 20;
      composerArray[i].multiline = true;
      composerArray[i].wordWrap = true;
      composerArray[i].autoSize = TextFieldAutoSize.LEFT;
      composerArray[i].text = musicInfoArray[i].Composer;
      composerArray[i].setTextFormat(titleFormat);
      resultsHolder.addChild(composerArray[i]);
               
      xPos += 130;
      // Next we make an array of text fields to hold our Song Description
      // Note that once again we use TextFieldAutoSize.LEFT for the autoSize property
      descArray[i] = new TextField();
      descArray[i].x = xPos;
      descArray[i].y = yPos;
      descArray[i].width = 160;
      descArray[i].height = 20;
      descArray[i].multiline = true;
      descArray[i].wordWrap = true;
      descArray[i].autoSize = TextFieldAutoSize.LEFT;
      descArray[i].text = musicInfoArray[i].Desc;
      descArray[i].setTextFormat(titleFormat);
      resultsHolder.addChild(descArray[i]);
               
      xPos += 160;
      // Now we make an array of buttons to act as our Buy button
      // We use the name property and assign it a value of i so that we can tell which button has been clicked
      buyArray[i] = new Button();
      buyArray[i].x = xPos + 2.5;
      buyArray[i].y = yPos;
      buyArray[i].width = 35;
      buyArray[i].height = 20;
      buyArray[i].label = "Buy";
      buyArray[i].name = i;
      buyArray[i].useHandCursor = true;
      buyArray[i].addEventListener(MouseEvent.CLICK, buyHandler);
      resultsHolder.addChild(buyArray[i]);


Using a for loop we start to add our results to our resultsHolder container. First we create the bar so it will sit underneath everything else. Down near the bottom of this class you will find a function called createSprite, which does just that. We pass the parameters of barColor, the width, the height, the xPos and the yPos to the createSprite class. Our bar lives in the array called barArray.

Now we add 2 pixels to our yPos. This is because I want to center the text vertically inside the bar which we created. The bar is 24 pixels in height and the text is set up to be 20 pixels in height, so that by adding 2 pixels to our yPos our text will now have a 2 pixel margin on top and bottom. Provided the text is a single line, of course. If it isn't, well, we'll deal with that in a minute.

Now we set up our titleArray, which will be an array of TextFields that will display our track titles. Notice that we give the TextField an initial height of 20, but set it's multiline and wordWrap properties to true and set the autoSize property to LEFT. What this does is maintain the width of the TextField, but, should there be more text than is capable of fitting in the set width, the TextField will automatically adjust it's height to
accommodate the extra text. Remember our musicInfoArray where we stored all of our song properties in an object? Here's where we get to use them. The first track title will be taken from the musicInfoArray[i].Track. Here i is the first object in the musicInfoArray and .Track is one of the properties of that object. Then we set our TextFormat property and finally we add it to our resultsHolder container.

The next bit of information we are going to display is our song length, and since this value won't ever exceed the width we've set for this TextField, we don't have to use the autoSize property. Again, the information we want is inside of musicInfoArray[i].Tracklength property.

Using the same technique we used for our titleArray, we add in our composerArray and descArray information.

When we get down to the buyArray it is a wee bit different. First of all, it is going to be an array of buttons. If you recall, the buyHead TextField was set up to be 40 pixels in width. These buttons are going to be 35 pixels wide, but I don't want them jammed up to the left with a gap on the right. I want them centered horizontally within the 40 pixels. So, we add 2.5 to the xPos. The other thing to note is that we are giving the
buttons a name property and setting that property to the value of i. We do this so that when a button is clicked we can use the name property value as an index to get at whatever other information we want that is inside the musicInfoArray. Lastly we add it to our resultsHolder container.
// Because one of the three text fields using the autoSize property could be larger than our bar height
      // we need to check and see which one is the biggest and then adjust the bar height to suit
      // Once we've figured out the new bar height, we adjust our y position so that the next item will line up properly
      if(descArray[i].height > 20 || titleArray[i].height > 20 || composerArray[i].height > 20){
        if(descArray[i].height >= titleArray[i].height && descArray[i].height >= composerArray[i].height){
          barArray[i].height = descArray[i].height + 2;
          yPos += bar1Array[i].height - 2;
      }
      if(titleArray[i].height >= descArray[i].height && titleArray[i].height >= composerArray[i].height){
        barArray[i].height = titleArray[i].height + 2;
        yPos += bar1Array[i].height - 2;
      }
      if(composerArray[i].height >= descArray[i].height && composerArray[i].height >= titleArray[i].height){
        barArray[i].height = composerArray[i].height + 2;
        yPos += bar1Array[i].height - 2;
      }
      // If none of the text fields is larger than the bar height, we adjust our y position so that the next item will line up properly
      }else{
        yPos += 23;
      }
      // We want the bars to be alternating colors so we switch the barColor by determining which color is it currently and then assigning
      // it the opposite color
      if(barColor == bar1Color){
        barColor = bar2Color;
      }else{
        barColor = bar1Color;
      }
      // Reset out x position to 0 and add in the next item
      xPos = 0;
    }
    // Once all the items are on stage, if we are using a bottom next/prev widget we add some space to our y position
    yPos += 17;


We went to a lot of trouble to accommodate unknown lengths of text. In the demo you'll notice that some of the descriptions are pretty long. Now that we have all that set up, we have to deal with it. We have three TextFields set to autoSize, so we need to check each of those TextFields to see if they have grown beyond their default height.

The first if statement checks to see if the descArray[i] TextField's height is greater than 20, or if the titleArray[i] TextField's height is greater than 20, or if the composerArray[i] TextField's height is greater than 20. If any of those conditions is true, then we start our secondary checks to see which of our TextFields is the highest. We want to increase the height of barArray[i] to match the highest of the three TextFields. So, if descArray[i].height is greater than or equal to titleArray[i].height and descArray[i].height is greater than or equal to composerArray[i].height, then the descArray is the highest, so we set the barArray[i].height to equal the descArray[i].height and add 2 just to keep our little margin, at least on top. Now we recalculate the yPos to take this new circumstance into account by taking the current yPos and adding in the new barArray[i].height minus the 2 pixels we added for the margin. If the descArray isn't the highest, then we run the same tests on the other two arrays. And, if all the arrays remain within the 20 pixels height, then we simply add 23 pixels to our existing yPos and carry on.

The next thing we want to do is change the bar color. We want to alternate the colors so things stand out nicely, so what we do is check to see which color the current barColor is, and then change to the other one. So if barColor is equal to bar1Color then set barColor to equal bar2Color, and vice versa.

The last thing we want to do before returning to the top of the loop and adding the next item is reset our xPos to 0.

Once we've looped through all the results, we add 17 to our yPos. The 17 is just an arbitary number to give us a wee bit of space. It can be as much or a little as you want it to be.
// We check once again to see if the boolean useNP is true and if the boolean firstPage is true
    // If both of those variables are true, we set up the next/prev widget the same as the top next/prev
    // except for the name property
    // Our y position is made up from the current yPos (which was set to 0 when we started to build the results) plus the height of the elements
    // at the very top plus a 10 pixel margin, so in this case we need 75 pixels for the top bits plus 10 for the margin
    if(useNP && firstPage){
      itemsToShow = maxNum;
      npB = new NextPrev(numSongs, maxNum, maxNum, 0x000000, 0x000000);
      npB.x = ((stage.stageWidth - (npB.width - 40))/2);
      npB.y = yPos + 85;
      npB.name = "NPB";
      npB.addEventListener(CustomEvent.CUSTOM, reBuild, false, 0, true);
      addChildAt(npB, 0);
      // If the boolean useNP is true, but firstPage is false, we need only to reposition our next/prev widget
    }else if(useNP && !firstPage){
      npB.y = yPos + 85;
    }
    // Once the first page is set up we set our boolean firstPage to false
    firstPage = false;
}


Now, if you are using both a top and a bottom instance of the NextPrev class, here is where you'll want to add in the second instance. First check to make sure that useNP is true and that firstPage is true. Then set it up exactly the same as the first instance, except that you will give it a different name to differentiate it from the top instance.  In this case I've called it NPB. The y position is set to yPos + 85 in this case because our elements on top use 75 pixels, our yPos is currently set to reflect the resultsHolder container and I want a 10 pixel margin between the resultsHolder and the npB instance.

Alternately, if useNP is true, but firstPage is not, then the only thing we will have to do is adjust the existing instance of npB's y position using the same rational as explained just above.

Finally we set our firstPage variable to false.

Next up is our buyHandler function.
private function buyHandler(e:MouseEvent):void{
  var musicIndex:int = e.target.name;
  trace("Item Clicked = " + musicIndex);
}


This function is much simplier than it would be under normal operating conditions. Here it just shows you which item has been clicked. If you click the first item it will trace 0. Why 0? Because arrays use a zero based index. So to get the track title of the first item we would use musicInfoArray[musicIndex].TrackTitle, where musicIndex is equal to 0. Presumably you would at this point be gathering information to enable someone to buy the item they have clicked, but that code is up to you to put into place depending on your circumstances.

The next function comes into play when either the next or Prev buttons are clicked. It is called inside of the NextPrev class. Remember that when we set up our instances npT and npB we added an event listener with the function set to reBuild. So, when you click either the Prev or Next buttons, the NextPrev class manipulates the data and sends the updated data back to our Document Class via our CustomEvent.
public function reBuild(e:CustomEvent):void{
  showingItem = e.arg[0];
  itemStart = e.arg[1];
  itemsToShow = e.arg[2];
  nBtn = e.arg[3];
  pBtn = e.arg[4];
  removeChild(resultsHolder);
  trace("Cur Target Name: " + e.currentTarget.name);
  if(e.currentTarget.name == "NPT"){
    npB.manualUpdate(showingItem, itemStart, itemsToShow, nBtn, pBtn);
  }else if(e.currentTarget.name == "NPB"){
    npT.manualUpdate(showingItem, itemStart, itemsToShow, nBtn, pBtn);
    /*if (ExternalInterface.available) {  
      ExternalInterface.call("backToTop");  
    }else{
      trace("ExternalInterface not available");
    }*/

  }
  buildResults();
}


The first thing to make note of is that this is declared as a public function. This is because it is being called from our NextPrev class so we need it to have inter-class operability. This uses our CustomEvent class to allow the event listener to pass a parameter. First I'll run through this function and then we'll take a side trip to have a look at our CustomEvent class.

The pieces of information we need in order to update the resultsHolder and the unclicked instance of NextPrev are taken from the array that is first prepared in the NextPrev class and then passed back. So, showingItem is set to equal e.arg[0], itemStart is set to equal e.arg[1] and so forth. Then we remove the existing resultsHolder in preparation for rebuilding it.

To update the unclicked NextPrev instance, we first determine which instance was clicked. So if e.currentTarget.name equals NPT, then we need to update the bottom instance, and vice versa if the name equals NPB. Now, if you are using a single instance of the Nextprev class, and therefore have not given it a name, you need not worry about an error creeping in here because Flash assigns every instance a name by default, and our if statements will simply be false and the program will move on. Once we know which instance has been clicked, we send the information gathered to the other instance and use the built in function in the NextPrev class called manualUpdate which will set the parameters in that instance to reflect the parameters in the instance that was clicked. We'll have a closer look at the manualUpdate function once we get to the NextPrev class.

If the instance of the NextPrev class that was clicked was the bottom one, then we use the ExternalInterface class to connect to a small bit of JavaScript we place on the html page holding our movie. It's commented out here since we won't be able to use it in this situation, but what's it for? Using the Actionscript.org tutorials as an example, when you are at the bottom of the page and you clicked next, did you end up back at the top of the page when the next page loaded? I get really grumpy if I don't get automatically taken back to the top of the next or previous page, so the way I make sure this doesn't happen to other people using my creations is to add the following bit of code to the html page and call the JavaScript function from Flash using the ExternalInterface. You will find this code in the backToTop.txt file included in the zip file.

Inbetween the <head> and </head> tags put the following:
<script type="text/javascript">
  function backToTop(){
    self.scrollTo(0,0);
  }
</script>


That simple function causes the page to scroll to a left position of 0 and a top position of 0. It is not likely that you will ever need to adjust the left position but, if, for instance, you had a 100 pixel high header on the page you would want to adjust the top position. The values would then be self.scrollTo(0, 100);.

Now that everything is lined up, we go back and do the buildResults() again.

The final function createSprite does just that.
private function createSprite(color:int, w:int, h:int, x:int, y:int):Sprite{
  var s:Sprite = new Sprite();
  s.graphics.beginFill(color);
  s.graphics.drawRect(0, 0, w, h);
  s.graphics.endFill();
  s.x = x;
  s.y = y;
  s.alpha = 1;
  addChild(s);
  return s;        
}


We pass in the color, width, height, x position, and y position and using this information the function draws a rectangle and returns us a shiny new Sprite.

Now let's take a look at our CustomEvent class before we move on and examine the NextPrev class.