10 Replies Latest reply on Feb 24, 2012 8:37 AM by BerubeS

    Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)

    UnfinishedDream Level 1

      Hi all,

       

      We have nicely skinned spark scrollbars in our application, but in the short term we're required to use the mx:Tree component (since the spark version is not available yet), which isn't compatible with our nice skins.  Creating MX scrollbar skins isn't really an option for us, so I was trying to figure out how to put a Tree component inside a s:Scroller.

       

      This might seem pretty straight forward, use the Scroller component to scroll up and down the Tree, instead of the mx:Tree's internal scrollbars.  Below I has some sample code from my test.  The problem seems to be the height of the mx:Tree.  How do you tell Flex to expland the Tree component to it's max size, instead of having to set the Tree height based on some external component?  Is there some value or reference within the mx:Tree that will indicate it's current height depending on what folders are open?

       

      In the example below, I have a mx:Tree inside a s:Scroller.  Once you open a couple folders, you can see the list uses the Tree's internal scrollbars instead of the s:Scroller's bars.  If I set the Tree height to 100%, this just makes it as big as the Scroller, and doesn't use the Scroller's scrollbars.

       

      <?xml version="1.0" encoding="utf-8"?>
      <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
                     xmlns:s="library://ns.adobe.com/flex/spark"
                     xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
          <s:Scroller height="400"
                      verticalScrollPolicy="on"
                      horizontalScrollPolicy="on"
                      color="red"
                      >
              <s:Group id="treeColumn" left="10" right="10" top="10" bottom="10">
                  <mx:Tree verticalScrollPolicy="auto"
                           height="100%"
                           width="200"
                           id="dirTree"
                           labelField="@label"
                           >
                      <mx:XMLListCollection id="MailBox">
                          <fx:XMLList>
                              <folder label="Mail">
                                  <folder label="INBOX"/>
                                  <folder label="Personal Folder">
                                      <Pfolder label="Business" />
                                      <Pfolder label="Demo" />
                                      <Pfolder label="Personal" isBranch="true" />
                                      <Pfolder label="Saved Mail" />
                                  </folder>
                                  <folder label="Personal Folder">
                                      <Pfolder label="Business" />
                                      <Pfolder label="Demo" />
                                      <Pfolder label="Personal" isBranch="true" />
                                      <Pfolder label="Saved Mail" />
                                      <Pfolder label="Business" />
                                      <Pfolder label="Demo" />
                                      <Pfolder label="Personal" isBranch="true" />
                                      <Pfolder label="Saved Mail" />
                                  </folder>
                                  <folder label="Sent" />
                                  <folder label="Trash" />
                              </folder>
                          </fx:XMLList>
                      </mx:XMLListCollection>
                  </mx:Tree>
              </s:Group>
          </s:Scroller>       
      </s:Application>

       

       

      Any thoughts or suggestions would be most welcome.  Thank you,

       

      dana.

        • 1. Re: Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)
          Flex harUI Adobe Employee

          I think I would use the Spark Tree prototype on my blog.

          • 2. Re: Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)
            UnfinishedDream Level 1

            Switching to the new Spark Tree sounds like it would require a fair investment of time to re-skin everything we're already done.  You replied to another skinning post which took quite a while to solve.

             

            Any change there are other options for adding a scroll bar to an mx:Tree?  Hiow complete or full featured is your spark Tree you created? I assume this is the blog post you are talking about: http://blogs.adobe.com/aharui/tag/spark-tree

             

            Thanks,

             

            dana.

            • 3. Re: Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)
              Flex harUI Adobe Employee

              Your choices probably are:

               

              1) Make the mx:Tree tall enough to hold every renderer so the scroller will

              do the right thing.  That could get quite expensive if there are lots of

              rows.

               

              2) Do some custom code to subclass Tree and have it report content size so

              the scroller will do the right thing.

               

              3) Use the prototype from my blog.  It uses Spark List.  There will likely

              be a bugs since it is a prototype, but at least you are working entirely in

              Spark.

              • 4. Re: Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)
                UnfinishedDream Level 1

                Thank you Alex, you set me on the right track.

                 

                I decided to go with option 2), which I thought would require the least time and pain.  After much testing and sleuthing through the AS Reference, I found the 'measureHeightOfItems()' method of ListBase, which returns the total height of all open items in the list.

                 

                For others who have had similar issues, I simply set the tree's height to the methods result, and executed the change on itemOpen/Close as listed below.  So all in all it worked out without having to extend the mx:Tree as well.

                 

                            <mx:Tree verticalScrollPolicy="auto"
                                     height="100%"
                                     width="200"
                                     id="dirTree"
                                     labelField="@label"

                                     itemClose="{dirTree.height = dirTree.measureHeightOfItems();}"
                                     itemOpen="{dirTree.height = dirTree.measureHeightOfItems();}"

                                     >

                 

                Thanks Alex,

                 

                dana.

                 

                 

                Edit:  I fixed some spelling and grammer.

                • 5. Re: Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)
                  Flex harUI Adobe Employee

                  It looks like you actually did option 1.  If you have lots of rows you may

                  run into memory issues.

                   

                  Good luck,

                  -Alex

                  • 6. Re: Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)
                    UnfinishedDream Level 1

                    Ah, thank you for the correction.  Yes you are right, I went the route of option 1, not 2. 

                     

                    We are using the mx:Tree to represent a file system directory, folder only, not files.  So potentially hundreds of folders, though unlikely thousands.  The tree component would likely only need to be resized when a user closes/opens a folder in the tree.  What type of memory issues might you anticipate?  Is it a one time performance hit for each click, or would it be an ongoing issue after user interaction? 

                     

                    Thanks,

                     

                    dana.

                    • 7. Re: Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)
                      Flex harUI Adobe Employee

                      Basically, the more display objects that are hooked up to the stage, the

                      more memory and CPU your app will consume, which can affect performance.

                      Even though you can only see a few rows of the tree, if there are 1000's of

                      rows you can't see only because they are clipped by the scroller, you will

                      be paying most of the price in memory and CPU.  That's why the Tree defaults

                      to virtual renderers.  It only wants to create display objects for the rows

                      you can see.

                       

                      With 1000's of rows, your users may notice that CPU utilization of the app

                      is noticeable, even if the app isn't being used.

                      • 9. Re: Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)
                        Woolloff Level 1

                        Option 4 - No memory or cpu issues, no event handlers other than mouseWheel (optional) are necessary, simply hides the mx scrollbar and binds the spark scrollbar to the relevant properties of the tree:

                         

                        <!-- WITHOUT MOUSEWHEEL HANDLING -->

                        <s:HGroup id="scrollableGroup"

                            width="100%" height="100%" gap="0"

                            >

                            <mx:Tree id="legacyTree"

                                width="100%" height="100%"

                                verticalScrollPolicy="{ScrollPolicy.OFF}"

                                contentBackgroundAlpha="0"

                                borderVisible="false"

                                />

                         

                            <s:VScrollBar id="legacyTreeScrollBar"

                                height="100%"

                                maximum="{legacyTree.maxVerticalScrollPosition}"

                                minimum="0"

                                value="@{legacyTree.verticalScrollPosition}"

                                />

                        </s:HGroup>

                         

                        <!-- WITH MOUSEWHEEL HANDLING -->

                        <fx:Script>

                            <![CDATA[

                                import mx.core.IInvalidating;

                                import mx.core.ScrollPolicy;

                         

                                protected function onLegacyTreeMouseWheel(event:MouseEvent):void

                                {

                                    if (event.isDefaultPrevented() || !legacyTree.visible)

                                        return;

                         

                                    const delta:int = event.delta;

                         

                                    var nSteps:uint = Math.abs(event.delta);

                         

                                    if (legacyTreeScrollBar && legacyTreeScrollBar.visible)

                                    {

                                        for (var vStep:int = 0; vStep < nSteps; vStep++)

                                        {

                                            var vspDelta:Number = 0;

                                            if (delta > 0 && (legacyTree.verticalScrollPosition - legacyTreeScrollBar.stepSize) >= 0)

                                                vspDelta = -legacyTreeScrollBar.stepSize;

                                            else if (delta < 0 && (legacyTree.verticalScrollPosition + legacyTreeScrollBar.stepSize) <= legacyTreeScrollBar.maximum)

                                                vspDelta = legacyTreeScrollBar.stepSize;

                         

                                            if (vspDelta != 0)

                                            {

                                                legacyTree.verticalScrollPosition += vspDelta;

                                                if (legacyTree is IInvalidating)

                                                    IInvalidating(legacyTree).validateNow();

                                            }

                                        }

                                        event.preventDefault();

                                    }

                                }

                            ]]>

                        </fx:Script>

                         

                        <s:HGroup id="scrollableGroup"

                            width="100%" height="100%" gap="0"

                            >

                            <mx:Tree id="legacyTree"

                                width="100%" height="100%"

                                verticalScrollPolicy="{ScrollPolicy.OFF}"

                                contentBackgroundAlpha="0"

                                borderVisible="false"

                                mouseWheel="onLegacyTreeMouseWheel(event)"

                                />

                         

                            <s:VScrollBar id="legacyTreeScrollBar"

                                height="100%"

                                maximum="{legacyTree.maxVerticalScrollPosition}"

                                minimum="0"

                                value="@{legacyTree.verticalScrollPosition}"

                                />

                        </s:HGroup>

                        • 10. Re: Spark scrollbars on a mx:Tree?  (Putting a mx:Tree in a s:Scroller)
                          BerubeS Level 1

                          Thank you for this solution. Here is a slightly improved one that allows horizontal scrolling and removes the scrollbars when not needed.

                           

                          This also uses the existing scrolling code you provider.

                           

                           

                          <s:VGroup>

                          <s:HGroup id="scrollableGroup" width="100%" height="100%" gap="0">

                               <mx:Tree  id="legacyTree" width="100%" height="100%" mouseWheel="legacyTree_mouseWheelHandler(event)"

                                               verticalScrollPolicy="{ScrollPolicy.OFF}"

                                                                                                                                        horizontalScrollPolicy="{ScrollPolicy.OFF}"

                                                                                                                                       labelField="displayName"

                                                                                                                                       dataProvider="{lifecycleTree}"/>

                          <s:VScrollBar id="legacyTreeVScrollBar"

                                                                                        height="100%"

                                                                                        visible="{(legacyTree.maxVerticalScrollPosition > 0)}"

                                                                                        maximum="{legacyTree.maxVerticalScrollPosition}"

                                                                                        minimum="0"

                                                                                        value="@{legacyTree.verticalScrollPosition}"/>

                          </s:HGroup>

                          <s:HScrollBar id="legacyTreeHScrollBar"

                                                                              width="100%"

                                                                              visible="{(legacyTree.maxHorizontalScrollPosition > 0)}"

                                                                              maximum="{legacyTree.maxHorizontalScrollPosition}"

                                                                              minimum="0"

                                                                              value="@{legacyTree.horizontalScrollPosition}"/>

                           

                          </s:VGroup>