Flex better datgrid

package 
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Point;

	import mx.collections.ArrayCollection;
	import mx.collections.CursorBookmark;
	import mx.controls.DataGrid;
	import mx.controls.dataGridClasses.DataGridColumn;
	import mx.controls.listClasses.IListItemRenderer;
	import mx.core.mx_internal;

	use namespace mx_internal;

	/**
	 *  A DataGrid subclass that has faster horizontal scrolling
	 */
	public class BetterDataGrid extends DataGrid
	{


		/**
		 * draw ground color for every row
		 */
		override protected function drawRowBackground(s:Sprite, rowIndex:int, y:Number, height:Number, color:uint, dataIndex:int):void
		{
		super.drawRowBackground(s, rowIndex, y, height, color, dataIndex);

		}




		public function BetterDataGrid()
		{
			super();
		}

		/**
		 *  remember the number of columns in case it changes
		 */
		private var lastNumberOfColumns:int;

		/**
		 *  a flag as to whether we can use the optimized scrolling
		 */
		private var canUseScrollH:Boolean;

		/**
		 *  when the horizontal scrollbar is changed it will eventually set horizontalScrollPosition
		 *  This value can be set programmatically as well.
		 */
		override public function set horizontalScrollPosition(value:Number):void
		{
			// remember the setting of this flag.  We will tweak it in order to keep DataGrid from
			// doing its default horizontal scroll which essentially refreshes every renderer
			var lastItemsSizeChanged:Boolean=itemsSizeChanged;

			// remember the current number of visible columns.  This can get changed by DataGrid
			// as it recomputes the visible columns when horizontally scrolled.
			lastNumberOfColumns=visibleColumns.length;

			// reset the flag for whether we use our new technique
			canUseScrollH=false;

			// call the base class.  If we can use our technique we'll trip that flag
			super.horizontalScrollPosition=value;

			// if the flag got tripped run our new technique
			if (canUseScrollH)
			{
				scrollLeftOrRight();
				configureScrollBars();
			}

			// reset the flag
			itemsSizeChanged=lastItemsSizeChanged;

		}

		// remember the parameters to scrollHorizontally to be used in our new technique
		private var pos:int;
		private var deltaPos:int;
		private var scrollUp:Boolean;

		public function get attrColumnIndex():int
		{

			return _attrColumnIndex;
		}

		public function set attrColumnIndex(o:int):void
		{
			_attrColumnIndex=o;
		}

		protected var _attrColumnIndex:int=0;


		// override this method.  If it gets called that means we can use the new technique
		override protected function scrollHorizontally(pos:int, deltaPos:int, scrollUp:Boolean):void
		{
			// just remember the args for later;
			this.pos=pos;
			this.deltaPos=deltaPos;
			this.scrollUp=scrollUp;
			if (deltaPos < visibleColumns.length)
			{
				canUseScrollH=true;

				// need this to prevent DG from asking for a full refresh
				itemsSizeChanged=true;
			}
		}

		/**
		 *  The new technique does roughly what we do vertically.  We shift the renderers on screen and in the
		 *  listItems array and only make the new renderers.
		 *  Because we can't get internal access to the header, we fully refresh it, but that's only one row
		 *  of renderers.  There's significant gains to be made by not fully refreshing the every row of columns
		 *
		 *  Key thing to note here is that visibleColumns has been updated, but the renderer array has not
		 *  That's why we don't do this in scrollHorizontally as the visibleColumns hasn't been updated yet
		 *  But because of that, sometimes we have to measure old renderers, and sometimes we measure the columns
		 */
		private function scrollLeftOrRight():void
		{
			// trace("scrollHorizontally " + pos);
			var i:int;
			var j:int;

			var numCols:int;
			var uid:String;

			var curX:Number;

			var rowCount:int=rowInfo.length;
			var columnCount:int=listItems[0].length;
			var cursorPos:CursorBookmark;

			var moveBlockDistance:Number=0;

			var c:DataGridColumn;
			var item:IListItemRenderer;
			var itemSize:Point;
			var data:Object;

			var xx:Number;
			var yy:Number;

			if (scrollUp) // actually, rows move left
			{
				// determine how many columns we're discarding
				var discardCols:int=deltaPos;

				// measure how far we have to move by measuring the width of the columns we
				// are discarding

				moveBlockDistance=sumColumnWidths(discardCols, true);
				// trace("moveBlockDistance = " + moveBlockDistance);

				//  shift rows leftward and toss the ones going away
				for (i=0; i < rowCount; i++)
				{
					numCols=listItems[i].length;

					if (numCols == 0) //empty row
					{
						continue;
					}

					// move the positions of the row, the item renderers for the row,
					// and the indicators for the row
					moveRowHorizontally(i, discardCols, -moveBlockDistance, numCols);
					// move the renderers within the array of rows
					shiftColumns(i, discardCols, numCols);
					truncateRowArray(i);
				}

				// generate replacement columns
				cursorPos=iterator.bookmark;

				var firstNewColumn:int=lastNumberOfColumns - deltaPos;
				curX=listItems[0][firstNewColumn - 1].x + listItems[0][firstNewColumn - 1].width;


				for (i=0; i < rowCount; i++)
				{
					if (iterator == null || iterator.afterLast || !iteratorValid)
						continue;
					data=iterator.current;
					iterator.moveNext();
					uid=itemToUID(data);

					xx=curX;
					yy=rowInfo[i].y;
					for (j=firstNewColumn; j < visibleColumns.length; j++)
					{
						c=visibleColumns[j];
						item=setupColumnItemRenderer(c, listContent, i, j, data, uid);
						//if(!item) return;
						itemSize=layoutColumnItemRenderer(c, item, xx, yy);
						xx+=itemSize.x;
					}
					// toss excess columns
					while (listItems[i].length > visibleColumns.length)
					{
						addToFreeItemRenderers(listItems[i].pop());
					}
				}

				iterator.seek(cursorPos, 0);
			}
			else
			{
				numCols=listItems[0].length;

				if (deltaPos > visibleColumns.length)
					deltaPos=visibleColumns.length;

				moveBlockDistance=sumColumnWidths(deltaPos, false);

				// shift the renderers and slots in array
				for (i=0; i < rowCount; i++)
				{
					numCols=listItems[i].length;
					if (numCols == 0)
						continue;

					moveRowHorizontally(i, 0, moveBlockDistance, numCols);
					// we add placeholders at the front for new renderers
					addColumnPlaceHolders(i, deltaPos);

				}

				cursorPos=iterator.bookmark;

				for (i=0; i < rowCount; i++)
				{
					data=iterator.current;
					iterator.moveNext();
					uid=itemToUID(data);

					xx=0;
					yy=rowInfo[i].y;
					for (j=0; j < deltaPos; j++)
					{
						c=visibleColumns[j];
						item=setupColumnItemRenderer(c, listContent, i, j, data, uid);
						itemSize=layoutColumnItemRenderer(c, item, xx, yy);
						xx+=itemSize.x;
					}
					// toss excess columns
					while (listItems[i].length > visibleColumns.length)
					{
						addToFreeItemRenderers(listItems[i].pop());
					}
				}

				iterator.seek(cursorPos, 0);
			}

			// force update the header
			header.headerItemsChanged=true;
			header.visibleColumns=visibleColumns;
			header.invalidateDisplayList();
			header.validateNow();

			// draw column lines and backgrounds
			drawLinesAndColumnBackgrounds();
		}

		/* override protected function addToFreeItemRenderers(item:IListItemRenderer):void
		{
		if (item) super.addToFreeItemRenderers(item);
		} */

		// if moving left, add up old renderers
		// if moving right, add up new columns
		private function sumColumnWidths(num:int, left:Boolean):Number
		{
			var i:int;
			var value:Number=0;
			if (left)
			{
				for (i=0; i < num; i++)
				{
					value+=listItems[0][i].width;
				}
			}
			else
				for (i=0; i < num; i++)
				{
					value+=visibleColumns[i].width;
				}

			return value;
		}

		// shift position of renderers on screen
		private function moveRowHorizontally(rowIndex:int, start:int, distance:Number, end:int):void
		{
			for (; start < end; start++)
				if (listItems[rowIndex][start])
				{
					listItems[rowIndex][start].x+=distance;
				}
		}

		// shift renderer assignments in listItems array
		private function shiftColumns(rowIndex:int, shift:int, numCols:int):void
		{
			var item:IListItemRenderer;
			var uid:String=itemToUID(listItems[rowIndex][0].data);
			for (var i:int=0; i < shift; i++)
			{
				item=listItems[rowIndex].shift();
				if (item)
				{
					addToFreeItemRenderers(item);
				}
			}
			//rebuild the listContent.visibleData map entry
			listContent.visibleData[uid]=listItems[rowIndex][0];
		}

		// add places in front of row for new columns
		private function addColumnPlaceHolders(rowIndex:int, count:int):void
		{
			for (var i:int=0; i < count; i++)
			{
				listItems[rowIndex].unshift(null);
			}
		}

		// remove excess columns
		private function truncateRowArray(rowIndex:int):void
		{
			while (listItems[rowIndex].length > visibleColumns.length)
			{
				var item:IListItemRenderer;
				{
					item=listItems[rowIndex].pop();
					addToFreeItemRenderers(item);
				}
			}
		}

		override protected function drawVerticalLine(s:Sprite, colIndex:int, color:uint, x:Number):void
		{
			if (!attrColumnIndex)
			{
				super.drawVerticalLine(s, colIndex, color, x);
				return;
			}
			if (colIndex == attrColumnIndex - pos)
			{
				var colour:uint=0xFF0000;
				super.drawVerticalLine(s, colIndex, colour, x);
				return;
			}
			super.drawVerticalLine(s, colIndex, color, x);
		}

	}
}

你可能感兴趣的:(优化,datagrid,Flex,fastScrolling)