11 Replies Latest reply on Jan 21, 2010 9:54 PM by WebTrauma

    Update cell Sprite in DataGrid

    WebTrauma Level 1

      Hi,

       

      I have a datagrid with a LOT of sprites (1700 circles, squares, and triangles) that I created in an itemRenderer in Actionscript using Peter Ent's excellent tutorial on custom item renderers. http://www.adobe.com/devnet/flex/articles/itemrenderers_pt5_03.html. Therefore, the Sprites inherit from UIComponent.

       

      I need to dynamically update a few of these sprites based on new data I pull down from the server once per minute.

       

      A full-page refresh is to be avoided since it takes 3-4 seconds to load and is disruptive to the user experience.

       

      Getting the row/column # from the datagrid's itemClick event is dead simple, but I don't see my Sprite when I look at the data using the debugger.

       

      What is the syntax to retrieve a given cell's Sprite from the application? Also, once I have that Sprite, how do I update/replace a Sprite only in that cell?

       

      Please help.

       

      Thanks!!!

       

       

        • 1. Re: Update cell Sprite in DataGrid
          Flex harUI Adobe Employee

          Hopefully, Peter Ent's blog explained that renderers get recycled and thus

          their appearance should be completely data-driven.  If you manipulate the

          renderer directly that manipulation could end up somewhere else during

          scrolling.

           

          If you do that, then you won't need to use ITEM_CLICK.  Once the data

          updates, the sprites in the renderer would also update.

          • 2. Re: Update cell Sprite in DataGrid
            WebTrauma Level 1

            Wow! Just wow. I tested updating the grid, and you're right...the sprite updated totally automatically.

             

            However, it looks like it's adding a new row at the top and pushing the other rows down. When the other rows are pushed down, they draw Sprites on top of the existing sprites.

             

            What I did for my test was to copy my test array into a button function, then changed the data value for the first row. Each subsequent button push adds another row to my grid, which pushes the other data down.

             

            How do I stop the update from adding rows???

             

            Thanks again for being patient with a newb!!!

            • 3. Re: Update cell Sprite in DataGrid
              Flex harUI Adobe Employee

              First I would verify that it is adding rows.  Check dataProvider.length.  If

              it isn't adding rows, then you are dealing with a recycling problem.  It is

              key that all the sprites are chosen based on the data object and that old

              existing sprites get removed or re-purposed.

              1 person found this helpful
              • 4. Re: Update cell Sprite in DataGrid
                WebTrauma Level 1

                 

                 

                 

                 

                 

                 

                You're right, it isn't adding rows.

                 

                I'm not sure what you mean by 'all the sprites are chosen based on the data  object and that old existing sprites get removed or re-purposed'.

                 

                I have 3 grids, but for the sake of simplicity will focus on just 1.

                 

                There are 39 rows and 15 columns. Each has a Sprite. At the moment, each column has its own custom ItemRenderer since there are data tags unique to each. I've noticed that the whole Object is passed in, so I *could* have one ginormous class to create Sprites for all 15 columns of a row at once, but (1) it didn't work to put that ItemRenderer at the datagrid level versus the individual column level and (2) I'm not sure which is more efficient.

                 

                Anyway, back to the most pressing problem: how to update Sprites in the grid from data updates.

                 

                Here is the code for the custom Item Renderer:

                 

                package utilities
                {
                     import flash.display.Sprite;
                     
                     import mx.controls.ToolTip;
                     import mx.controls.listClasses.IListItemRenderer;
                     import mx.core.UIComponent;
                     import mx.events.FlexEvent;
                     
                     public class Drop1Renderer extends UIComponent implements IListItemRenderer
                     {
                          
                          public function Drop1Renderer()
                          {
                               super();
                               height=20;
                               width=16;
                          }
                          // Internal variable for property
                          private var _data:Object;
                          
                          // Make it bindable
                          [Bindable("dataChange")]
                          
                          // Define the getter
                          public function get data():Object 
                          {
                               return _data;
                          }
                          
                          //define the setter
                          public function set data(value:Object):void
                          {
                               _data = value;
                               invalidateProperties();
                               dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
                               
                               if (value.deviceType1 != "Null") 
                               {
                                    var mySprite:Sprite = new Sprite(); 
                                    mySprite.cacheAsBitmap=false;
                                    buttonMode=true;
                                    
                                    var uic:UIComponent = new UIComponent(); 
                                    mySprite.graphics.beginFill(value.deviceColor1); 
                                    var triangleHeight:Number = 12;
                                         
                                    switch (value.deviceType1) 
                                    {
                                         case "Circle":
                                              mySprite.graphics.lineStyle(1,0x000000, .5);
                                              mySprite.graphics.drawCircle(8, 9, 5); 
                                              break;
                                         case "CircleBlue":
                                              mySprite.graphics.lineStyle(2,0x0000DD, .9);
                                              mySprite.graphics.drawCircle(8, 9, 5); 
                                              break;
                                         
                                         case "TriangleRed":
                                              mySprite.graphics.lineStyle(2,0xFF0000, .9);
                                              mySprite.graphics.moveTo((triangleHeight/2)+2, 3);
                                              mySprite.graphics.lineTo(triangleHeight+2, triangleHeight+1);
                                              mySprite.graphics.lineTo(2, triangleHeight+1);
                                              mySprite.graphics.lineTo((triangleHeight/2)+2, 3);
                                              break;
                                         case "Triangle":
                                              mySprite.graphics.lineStyle(1,0x000000, .5);
                                              mySprite.graphics.moveTo((triangleHeight/2)+2, 3);
                                              mySprite.graphics.lineTo(triangleHeight+2, triangleHeight+1);
                                              mySprite.graphics.lineTo(2, triangleHeight+1);
                                              mySprite.graphics.lineTo((triangleHeight/2)+2, 3);
                                              break;
                                         case "TriangleBlue":
                                              mySprite.graphics.lineStyle(2,0x0000DD, .9);
                                              mySprite.graphics.moveTo((triangleHeight/2)+2, 3);
                                              mySprite.graphics.lineTo(triangleHeight+2, triangleHeight+1);
                                              mySprite.graphics.lineTo(2, triangleHeight+1);
                                              mySprite.graphics.lineTo((triangleHeight/2)+2, 3);
                                              break;
                                         
                                         case "Rect":
                                              mySprite.graphics.lineStyle(1,0x000000, .5);
                                              mySprite.graphics.drawRect(3, 4, 10, 10); 
                                              break;
                                         case "RectBlue":
                                              mySprite.graphics.lineStyle(2,0x0000DD, .9);
                                              mySprite.graphics.drawRect(3, 4, 10, 10); 
                                              break;
                                         case "RectOrange":
                                              mySprite.graphics.lineStyle(2,0xFFA500, .9);
                                              mySprite.graphics.drawRect(3, 4, 10, 10); 
                                              break;
                                         
                                         case "Ellipse":
                                              mySprite.graphics.lineStyle(1,0x000000, .7);
                                              mySprite.graphics.drawEllipse(2, 5, 12, 6); 
                                              break;
                                              
                                         default:
                                              mySprite.graphics.drawCircle(8, 9, 5); 
                                         
                                    }
                                    uic.addChild(mySprite); 
                                    this.addChild(uic); 
                                    uic.toolTip = "Howdy there!";
                               }
                          
                          }
                          
                          //
                          override protected function createChildren() : void
                          {
                               super.createChildren();
                          }
                          
                          //
                          override protected function commitProperties() : void
                          {
                               super.commitProperties();
                          }
                          
                          //
                          override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
                          {
                               super.updateDisplayList(unscaledWidth, unscaledHeight);
                               
                          }
                          
                     }
                }

                .

                • 5. Re: Update cell Sprite in DataGrid
                  WebTrauma Level 1

                  Using the Flex debugger, in the ItemRenderer I don't see anything other than the passed in values.

                   

                  The Sprite is always null until it is (re)drawn.

                   

                  How then do I code the ItemRenderer to prevent a recycling problem???

                   

                  Thanks!

                  • 6. Re: Update cell Sprite in DataGrid
                    Flex harUI Adobe Employee

                    I would guess the problem is that you aren't resetting back to zero children

                    and keep piling on more children.

                    • 7. Re: Update cell Sprite in DataGrid
                      WebTrauma Level 1

                      How do you reset to zero children?

                       

                      Wouldn't this force a redraw of the whole grid? I was hoping to only have to redraw the Sprites that change, which would normally be 10% or less of the 1700 Sprites.

                       

                      Also, why can't I see references to the Sprite objects when I look at memory in the Debugger?

                       

                      Thanks!!!

                      • 8. Re: Update cell Sprite in DataGrid
                        Flex harUI Adobe Employee

                        Call removeChild on every child.

                         

                        But you are right that if you can recycle the Sprites already created you

                        will be better off, but be sure to remove or hide any that are no longer

                        needed.  Right now you are creating new ones every time the data changes.

                         

                        If you don't keep a reference to the sprites from some instance variable, it

                        will be much harder to see them in the debugger.

                        1 person found this helpful
                        • 9. Re: Update cell Sprite in DataGrid
                          WebTrauma Level 1

                          Thanks, Alex.

                           

                          When I try to removeChild(), I always get a null object reference.

                           

                          I tried adding a data value to prevent executing the update/draw logic. That does prevent the draw/add functions from executing, but I still get the duplicate icons. I looked it this in the debugger, and it works insofar as it skips the draw/add logic.

                           

                          if (value.updateSpr1 == true);

                                                                          {

                          ...draw/add logic

                          }

                           

                          I've attached a vastly simplified version of my code so you can see the exact conditions under which the problem occurs.

                           

                          Thanks again!!!

                          • 10. Re: Update cell Sprite in DataGrid
                            Flex harUI Adobe Employee

                            This is not a good week for me to poke into a lot of code.  Hopefully

                            someone else can help you out.

                            • 11. Re: Update cell Sprite in DataGrid
                              WebTrauma Level 1

                              No worries, Alex.

                               

                              My friend Rob hooked me up with the magic syntax (this.numChildren) to figure out whether or not a Child already exists. These lines in the ItemRenderer fixed the problem:

                               

                              if (this.numChildren > 0) 

                              {

                                    this.removeChildAt(0);

                              }


                              I also read your post on ItemRenderers, which was very helpful: http://blogs.adobe.com/aharui/2007/03/thinking_about_item_renderers_1.html

                               

                               

                              Thank you once again !!!