Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Adobe AIR Development

Reply
Developer
Posts: 1,003
Registered: ‎01-16-2011
My Device: PlayBook (sim)
My Carrier: Rogers

Re: Best way to implement an Excel style grid...

[ Edited ]

Just need to rant -

 

I've created a tileList, set up a CustomCellRenderer to put a textInput field into each cell, and it crashes the simulator everytime I click on a tile. Every time. I guess I've just been lucky up to this point having a simulator that rarely (if ever) crashes.

- If you like my response/post, or it helped you find an answer you were looking for, please provide a Kudo - white star to the bottom right of this post. -
- Please use the search bar at the top, or check out the PlayBook FAQ's for help getting started -
- Hockey DrillBook -
Regular Contributor
Posts: 51
Registered: ‎02-02-2011
My Device: Not Specified

Re: Best way to implement an Excel style grid...

@noahnu: Not sure why this is particularly inefficient?  The TileList only renders the items you are currently seeing so you shouldn't have to worry about there being too many.  depends I guess on your grid resolution.

Developer
Posts: 1,003
Registered: ‎01-16-2011
My Device: PlayBook (sim)
My Carrier: Rogers

Re: Best way to implement an Excel style grid...

[ Edited ]

Just wanted to post some code here to show what I've been able to put together.

In the end this is going to be an app that the user will add info to, save, and start from scratch the next day (kind of like a journal) so if I'm going about this the wrong way please let me know!

 

My Main.as file

 

package
{
	import flash.display.Sprite;
	
	import qnx.ui.data.DataProvider;
	import qnx.ui.listClasses.*;
	
	
	[SWF(height="600", width="1024", 
	frameRate="30", backgroundColor="#666666")]
	public class Main extends Sprite
	{
		public function Main()
		{
			initializeUI();
		}
		
		private function initializeUI():void
		{
			//this is the only way I've found to add more boxes to my grid. Any ideas?
var arr:Array=[]; arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); arr.push({label: ""}); var bg:Sprite = new Sprite(); bg.graphics.lineStyle(2,0xCCCCCC); bg.graphics.beginFill(0x333333,1); bg.graphics.drawRect(0,0,512,600); bg.graphics.endFill(); bg.x = 0; bg.y = 0; this.addChild(bg); var myTileList:TileList = new TileList(); myTileList.setPosition(0, 0); myTileList.width = 512; myTileList.height = 600; myTileList.cellPadding = 3; myTileList.columnCount = 8; myTileList.columnWidth = 60; myTileList.rowCount = 20; myTileList.rowHeight = 40; myTileList.setSkin(CustomCellRenderer); myTileList.selectionMode = ListSelectionMode.SINGLE; myTileList.dataProvider = new DataProvider(arr); this.addChild(myTileList); } } }

 My CustomCellRenderer.as

 

package
{
	import flash.text.*;
	
	import qnx.ui.listClasses.AlternatingCellRenderer;
	import qnx.ui.skins.SkinStates;
	
	public class CustomCellRenderer extends AlternatingCellRenderer
	{
		public function CustomCellRenderer()
		{
			super();
			
			var myFormat:TextFormat = new TextFormat();
			
			myFormat.align = TextFormatAlign.CENTER;
			
			
			setTextFormatForState(myFormat, SkinStates.UP);
			setTextFormatForState(myFormat, SkinStates.DOWN);
			setTextFormatForState(myFormat, SkinStates.SELECTED);
			setTextFormatForState(myFormat, SkinStates.DOWN_SELECTED);
			
			setSkin(CustomSkin);		
		}
	}
}
	

 And my CustomSkin.as

 

package
{
	import flash.display.Sprite;
	import flash.text.engine.SpaceJustifier;
	
	import qnx.ui.skins.SkinAssets;
	import qnx.ui.skins.SkinStates;
	import qnx.ui.skins.UISkin;
	import qnx.ui.text.TextInput;
	import qnx.ui.text.KeyboardType;
	import qnx.ui.text.ReturnKeyType;
	import qnx.ui.text.TextInputIconMode;
	
	
	public class CustomSkin extends UISkin
	{
		/**@private**/
		protected var upSkin:Sprite;
		/**@private**/
		protected var selectedSkin:Sprite;
		/**@private**/
		protected var disabledSkin:Sprite;
		/**@private**/
		protected var downSkin:Sprite;
		
		protected var upOddSkin:Sprite;
		protected var input:TextInput;
		public function CustomSkin()
		{
			super();
		}
		
		override protected function initializeStates():void 
		{
			
			upSkin = new Sprite();
			//upSkin.opaqueBackground = 1;
			//upSkin.graphics.beginFill(0x2b2b2b, .99);
			//upSkin.graphics.drawRect(0,0,200,200);
			//upSkin.graphics.endFill();
			
			input = new TextInput();
			input.setPosition(0,0);
			input.height = 40;
			input.keyboardType = KeyboardType.PHONE;
			input.returnKeyType = ReturnKeyType.CONNECT;
			upSkin.addChild(input);
			
			//upOddSkin = new Sprite();
			//upOddSkin.graphics.beginFill(0x222222, .99);
			//upOddSkin.graphics.drawRect(0,0,200,200);
			//upOddSkin.graphics.endFill();
			
			downSkin = new Sprite();
			//downSkin.graphics.beginFill(0x000000);
			//downSkin.graphics.drawRect(0,0,200,200);
			//downSkin.graphics.endFill();
			
			disabledSkin = new Sprite();
			disabledSkin.graphics.beginFill(0x000000);
			disabledSkin.graphics.drawRect(0,0,200,200);
			
			disabledSkin.graphics.endFill();
			
			//selectedSkin = new Sprite();
			//selectedSkin.graphics.beginFill(0x000000);
			//selectedSkin.graphics.drawRect(0,0,200,200);
			//selectedSkin.graphics.endFill();
			
			
			setSkinState(SkinStates.UP, upSkin );
			setSkinState(SkinStates.UP_ODD, upOddSkin );
			setSkinState(SkinStates.SELECTED,selectedSkin );
			setSkinState( SkinStates.DISABLED, disabledSkin );
			setSkinState( SkinStates.DOWN, downSkin );
			showSkin( upSkin );
			
		}
		
	}
}

 

 

(JRab if this code looks familiar I think most of it is borrowed from solutions you've posted lol)

 

 

- If you like my response/post, or it helped you find an answer you were looking for, please provide a Kudo - white star to the bottom right of this post. -
- Please use the search bar at the top, or check out the PlayBook FAQ's for help getting started -
- Hockey DrillBook -
Developer
Posts: 2,462
Registered: ‎11-04-2010
My Device: Bold 9700

Re: Best way to implement an Excel style grid...

[ Edited ]

hey jffurian,

 

great job so far with your custom data grid! glad you are taking bits and pieces from everywhere - that's why its here Smiley Happy

 

here are a few modifications i made (mostly aesthetic but some functionality). I removed the custom skin in the cell renderer, seems like more work than necessary. instead i added what you had into the cell renderer itsself. that way you only have to worry about one file instead of two. also, i got rid of the the delete icon to make more room to see your text in the textinput via the clearIconMode property of the TextInput. also to make the textinput fit in a little more, i applied a transparent version of the TextInput skin that makes the TextInput fit in just like it would in Excel (no borders). this was with the help of one of renaun's previous posts about applying skins. I sort of changed the size of your grid to make things fit a little better (800x600). Also reduced the cell padding to 1 to get a better look at things.

 

also of note instead of individually adding items to your array, you can do a for-loop. i cant think of a way without filling in blank data to get more cells either.

 

without further ado, here are the code files i used:

 

TileListGridTest.as:

 

 

package
{
import flash.display.Sprite;

import qnx.ui.data.DataProvider;
import qnx.ui.listClasses.*;


[SWF(height="600", width="1024", frameRate="30", backgroundColor="#666666")]
public class TileListGridTest extends Sprite
{
public function Main()
{
initializeUI();
}

private function initializeUI():void
{
//this is the only way I've found to add more boxes to my grid. Any ideas?
var arr:Array=[];

for (var i:int = 0; i < 100; i++)
{
arr.push({label: ""});
}


var bg:Sprite = new Sprite();
bg.graphics.lineStyle(2,0xCCCCCC);
bg.graphics.beginFill(0x333333,1);
bg.graphics.drawRect(0,0,800,600);
bg.graphics.endFill();
bg.x = 0;
bg.y = 0;
this.addChild(bg);

var myTileList:TileList = new TileList();
myTileList.setPosition(0, 0);
myTileList.cellPadding = 1;
myTileList.setSize(800, 600);
myTileList.columnCount = 10;
myTileList.columnWidth = 80;
myTileList.rowHeight = 60;
myTileList.setSkin(CustomCellRenderer);
myTileList.selectionMode = ListSelectionMode.SINGLE;
myTileList.dataProvider = new DataProvider(arr);
this.addChild(myTileList);
}
}
}

 

 

CustomCellRenderer.as:

 

 

package
{

import qnx.ui.listClasses.AlternatingCellRenderer;
import qnx.ui.skins.SkinStates;
import qnx.ui.text.KeyboardType;
import qnx.ui.text.ReturnKeyType;
import qnx.ui.text.TextInput;
import qnx.ui.text.TextInputIconMode;

public class CustomCellRenderer extends AlternatingCellRenderer
{
private var textInput:TextInput;

public function CustomCellRenderer()
{
super();
}

override protected function init():void
{
textInput = new TextInput();

super.init();
}

override protected function drawLabel():void
{
super.drawLabel();

if (!this.data)
{
return;
}

textInput.setSize(72,58);
textInput.setSkin(CustomTextInputSkin);
textInput.clearIconMode = TextInputIconMode.NEVER;
textInput.keyboardType = KeyboardType.PHONE;
textInput.returnKeyType = ReturnKeyType.CONNECT;

this.addChild(textInput);
}

override protected function onAdded():void
{
super.onAdded();

if (!this.contains(textInput))
this.addChild(textInput);
}

override protected function onRemoved():void
{
if (this.contains(textInput))
this.removeChild(textInput);
}
}
}

 

 

CustomTextInputSkin.as:

 

 

package
{
    import flash.display.Sprite;
    
    import qnx.ui.skins.SkinStates;
    import qnx.ui.skins.text.TextInputSkinWhite;
    
    public class CustomTextInputSkin extends TextInputSkinWhite
    {    
        [Embed(source="images/transparent_bg.png",
                scaleGridTop="18", scaleGridBottom="34",
                scaleGridLeft="18", scaleGridRight="352")]
        private var OddShapeSkin:Class;
        
        protected var skin1:Sprite;
        
        override protected function initializeStates():void
        {        
            super.initializeStates();
            skin1 = new OddShapeSkin();
            
            setSkinState(SkinStates.UP, skin1);
            setSkinState(SkinStates.DOWN, skin1);
            setSkinState(SkinStates.SELECTED, skin1);
            setSkinState(SkinStates.DISABLED, skin1);
            
            
        }
    }
}

 

I've also attached the transparent_bg.png file i used for the TextInput skin. hope this sheds a little more light on the whole subject. its most likely not perfect so any changes are welcomed. keep me posted on how far you get. good luck!

 

J. Rab (Blog) (Twitter)
--
1. If you liked my post or found it useful please click on the thumbs up and provide a Like!
2. If my post solved your problem please click on the Accept as Solution button. Much appreciated!

Approved Apps: OnTrack | ssShots | Hangman
Developer
Posts: 1,003
Registered: ‎01-16-2011
My Device: PlayBook (sim)
My Carrier: Rogers

Re: Best way to implement an Excel style grid...

JRab that's awesome. Aesthetics can be tricky and any help is always appreciated. It's definitely what I was looking for.

 

Now, as for saving data, if I wanted the user to fill the grid with data, save it, and start fresh, is it possible with this setup?

- If you like my response/post, or it helped you find an answer you were looking for, please provide a Kudo - white star to the bottom right of this post. -
- Please use the search bar at the top, or check out the PlayBook FAQ's for help getting started -
- Hockey DrillBook -
Developer
Posts: 2,462
Registered: ‎11-04-2010
My Device: Bold 9700

Re: Best way to implement an Excel style grid...

hey jffurian,

 

just did some tests and created three buttons to reset, save, and load the data of the grid. I had to add a few things to the to the CustomCellRenderer and the main application to work with the data being processed. the other files were untouched. first i created a base array to store the data. each save click creates a new position in the data array. and then the data is copied from the grid and saved. when you hit the load button, it will load the most recent save you did. also you can test it out using hte reset button and hitting load again to see that it saved.

 

also a note to how we are storing the data from the TextInput object, we are storing it in the cell's data object. we are adding a .text property to the data similar to the .label property that will store the text in each cell.

 

here's the code, if you need more explanation let me know:

 

TileListGridTest.as:

 

 

package
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	
	import qnx.ui.buttons.LabelButton;
	import qnx.ui.data.DataProvider;
	import qnx.ui.listClasses.*;
	
	
	[SWF(height="600", width="1024", frameRate="30", backgroundColor="#666666")]
	public class TileListGridTest extends Sprite
	{
		private var myTileList:TileList;
		
		private var resetBtn:LabelButton;
		private var saveBtn:LabelButton;
		private var loadBtn:LabelButton;
		
		private var dataArray:Array;
		private var currentPosition:int;
		
		public function TileListGridTest()
		{
			initializeUI();
		}
		
		private function initializeUI():void
		{
			dataArray = new Array();
			
			//this is the only way I've found to add more boxes to my grid. Any ideas?
			var arr:Array=[];
			
			for (var i:int = 0; i < 100; i++)
			{
				arr.push({label: ""});
			}
			
			
			var bg:Sprite = new Sprite();
			bg.graphics.lineStyle(2,0xCCCCCC);
			bg.graphics.beginFill(0x333333,1);
			bg.graphics.drawRect(0,0,800,600);
			bg.graphics.endFill();
			bg.x = 0;
			bg.y = 0;
			this.addChild(bg);
			
			myTileList = new TileList();
			
			myTileList.setPosition(0, 0);
			myTileList.cellPadding = 1;
			myTileList.setSize(800, 600);
			myTileList.columnCount = 10;
			myTileList.columnWidth = 80;
			myTileList.rowHeight = 60;
			myTileList.setSkin(CustomCellRenderer);
			myTileList.selectionMode = ListSelectionMode.SINGLE;
			myTileList.dataProvider = new DataProvider(arr);			
			this.addChild(myTileList);
			
			resetBtn = new LabelButton();
			resetBtn.label = "Reset";
			resetBtn.setSize(150, 52);
			resetBtn.setPosition(stage.stageWidth - resetBtn.width - 25,100);
			resetBtn.addEventListener(MouseEvent.CLICK, onResetClick);
			
			saveBtn = new LabelButton();
			saveBtn.label = "Save";
			saveBtn.setSize(150, 52);
			saveBtn.setPosition(resetBtn.x,resetBtn.y + resetBtn.height + 10);
			saveBtn.addEventListener(MouseEvent.CLICK, onSaveClick);
			
			loadBtn = new LabelButton();
			loadBtn.label = "Load";
			loadBtn.setSize(150, 52);
			loadBtn.setPosition(resetBtn.x,saveBtn.y + saveBtn.height + 10);
			loadBtn.addEventListener(MouseEvent.CLICK, onLoadClick);
			
			this.addChild(resetBtn);
			this.addChild(saveBtn);
			this.addChild(loadBtn);
			
		}
		
		private function onResetClick(e:MouseEvent):void
		{
			var arr:Array=[];
			
			for (var i:int = 0; i < 100; i++)
			{
				arr.push({label: ""});
			}
			
			myTileList.dataProvider.setItems(arr, true);
			
			trace("Reset");
		}
		
		private function onSaveClick(e:MouseEvent):void
		{
			dataArray[currentPosition] = new Array();
			
			for (var i:int = 0; i < myTileList.dataProvider.length; i++)
			{
				var myObj:Object = {text: myTileList.getItemAt(i).text}
				
				dataArray[currentPosition].push(myObj);
			}
			
			currentPosition++;
			
			trace("Saved");
		}
		
		private function onLoadClick(e:MouseEvent):void
		{
			var arr:Array=[];
			
			for (var i:int = 0; i < dataArray[currentPosition-1].length; i++)
			{
				arr.push({label: "", text: dataArray[currentPosition-1][i].text});
			}
			
			myTileList.dataProvider.setItems(arr, true);	
			
			trace("Loaded");
		}
	}
}

 

 

CustomCellRenderer.as:

 

 

package
{    
    
    import flash.events.Event;
    
    import qnx.ui.listClasses.AlternatingCellRenderer;
    import qnx.ui.skins.SkinStates;
    import qnx.ui.text.KeyboardType;
    import qnx.ui.text.ReturnKeyType;
    import qnx.ui.text.TextInput;
    import qnx.ui.text.TextInputIconMode;
    
    public class CustomCellRenderer extends AlternatingCellRenderer
    {
        private var textInput:TextInput;
        
        public function CustomCellRenderer()
        {
            super();
        }
        
        override protected function init():void
        {
            textInput = new TextInput();
            
            super.init();
        }
        
        override protected function drawLabel():void
        {
            super.drawLabel();
            
            if (!this.data)
            {
                return;
            }
            
            textInput.setSize(72,58);
            textInput.setSkin(CustomTextInputSkin);
            textInput.clearIconMode = TextInputIconMode.NEVER;
            textInput.keyboardType = KeyboardType.PHONE;
            textInput.returnKeyType = ReturnKeyType.CONNECT;
            textInput.addEventListener(Event.CHANGE, onChange);
            
            this.addChild(textInput);
        }
        
        override protected function onAdded():void
        {
            super.onAdded();
            
            if (!this.contains(textInput))
                this.addChild(textInput);
        }
        
        override protected function onRemoved():void
        {
            if (this.contains(textInput))
                this.removeChild(textInput);
        }
        
        private function onChange(e:Event):void
        {
            this.data.text = this.textInput.text;
        }

        
        override public function set data(data:Object):void
        {
            super.data = data;
            
            if (!data)
                return;
            
            /**
             * Each time the data is set to the cell we assume
             * new data or a reset was initiated.
             **/
            
            textInput.text = (this.data.text) ? this.data.text : "";
        }

    }
}

 

Also of note this is just a proof of concept so i dont know how efficient / inefficient this approach maybe. but it works Smiley Happy good luck!

 

J. Rab (Blog) (Twitter)
--
1. If you liked my post or found it useful please click on the thumbs up and provide a Like!
2. If my post solved your problem please click on the Accept as Solution button. Much appreciated!

Approved Apps: OnTrack | ssShots | Hangman
Highlighted
Developer
Posts: 1,003
Registered: ‎01-16-2011
My Device: PlayBook (sim)
My Carrier: Rogers

Re: Best way to implement an Excel style grid...

[ Edited ]

JRab,


I keep getting the following error, "Access of undefined propert myTileList", on every instance of myTileList after the line

        private function onResetClick(e:MouseEvent):void


Any ideas?

 

Nevermind lol

- If you like my response/post, or it helped you find an answer you were looking for, please provide a Kudo - white star to the bottom right of this post. -
- Please use the search bar at the top, or check out the PlayBook FAQ's for help getting started -
- Hockey DrillBook -